From 090dc34f3fcd92be3471039720602b261d5f8c20 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 1 Nov 2023 00:22:44 +0100 Subject: [PATCH 001/189] Stabilize Wasm relaxed SIMD --- src/attributes/codegen.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index e7de843..0ccc013 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -273,19 +273,21 @@ attempting to use instructions unsupported by the Wasm engine will fail at load time without the risk of being interpreted in a way different from what the compiler expected. -Feature | Description -----------------------|------------------- -`bulk-memory` | [WebAssembly bulk memory operations proposal][bulk-memory] -`extended-const` | [WebAssembly extended const expressions proposal][extended-const] -`mutable-globals` | [WebAssembly mutable global proposal][mutable-globals] -`nontrapping-fptoint` | [WebAssembly non-trapping float-to-int conversion proposal][nontrapping-fptoint] -`sign-ext` | [WebAssembly sign extension operators Proposal][sign-ext] -`simd128` | [WebAssembly simd proposal][simd128] +Feature | Implicitly Enables | Description +----------------------|---------------------|------------------- +`bulk-memory` | | [WebAssembly bulk memory operations proposal][bulk-memory] +`extended-const` | | [WebAssembly extended const expressions proposal][extended-const] +`mutable-globals` | | [WebAssembly mutable global proposal][mutable-globals] +`nontrapping-fptoint` | | [WebAssembly non-trapping float-to-int conversion proposal][nontrapping-fptoint] +`relaxed-simd` | `simd128` | [WebAssembly relaxed simd proposal][relaxed-simd] +`sign-ext` | | [WebAssembly sign extension operators Proposal][sign-ext] +`simd128` | | [WebAssembly simd proposal][simd128] [bulk-memory]: https://github.com/WebAssembly/bulk-memory-operations [extended-const]: https://github.com/WebAssembly/extended-const [mutable-globals]: https://github.com/WebAssembly/mutable-global [nontrapping-fptoint]: https://github.com/WebAssembly/nontrapping-float-to-int-conversions +[relaxed-simd]: https://github.com/WebAssembly/relaxed-simd [sign-ext]: https://github.com/WebAssembly/sign-extension-ops [simd128]: https://github.com/webassembly/simd From 3f1677b6a02bb022fa91ce472d01a450e7a073ed Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 4 Aug 2024 11:21:41 +0100 Subject: [PATCH 002/189] Say that `pub(in path)` may not rely on `use` statements --- src/visibility-and-privacy.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/visibility-and-privacy.md b/src/visibility-and-privacy.md index df9f05a..67fd133 100644 --- a/src/visibility-and-privacy.md +++ b/src/visibility-and-privacy.md @@ -147,8 +147,9 @@ expressions, types, etc. In addition to public and private, Rust allows users to declare an item as visible only within a given scope. The rules for `pub` restrictions are as follows: -- `pub(in path)` makes an item visible within the provided `path`. `path` must -be an ancestor module of the item whose visibility is being declared. +- `pub(in path)` makes an item visible within the provided `path`. + `path` must be a simple path which resolves to an ancestor module of the item whose visibility is being declared. + Each identifier in `path` must refer directly to a module (not to a name introduced by a `use` statement). - `pub(crate)` makes an item visible within the current crate. - `pub(super)` makes an item visible to the parent module. This is equivalent to `pub(in super)`. From 8061c718f5a151006a929d2d1047c2bf41013cc1 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 18 Jul 2024 13:05:50 -0300 Subject: [PATCH 003/189] Impact Unsafe extern blocks changes --- src/items/external-blocks.md | 69 ++++++++++++++++++------------------ src/items/functions.md | 2 +- src/types/never.md | 2 +- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 9abce3f..937cd92 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -23,37 +23,38 @@ blocks is only allowed in an `unsafe` context. The external block defines its functions and statics in the [value namespace] of the module or block where it is located. -The `unsafe` keyword is syntactically allowed to appear before the `extern` -keyword, but it is rejected at a semantic level. This allows macros to consume -the syntax and make use of the `unsafe` keyword, before removing it from the -token stream. +Starting in edition 2024, the `unsafe` keyword is required to appear before the +`extern` keyword. In previous editions is accepted but not required. ## Functions Functions within external blocks are declared in the same way as other Rust functions, with the exception that they must not have a body and are instead terminated by a semicolon. Patterns are not allowed in parameters, only -[IDENTIFIER] or `_` may be used. Function qualifiers (`const`, `async`, -`unsafe`, and `extern`) are not allowed. +[IDENTIFIER] or `_` may be used. Only safety funcion qualifiers are allowed +(`unsafe`, `safe`), other function qualifiers (`const`, `async`, and `extern`) +are not allowed. Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler automatically translates between the Rust ABI and the foreign ABI. -A function declared in an extern block is implicitly `unsafe`. When coerced to -a function pointer, a function declared in an extern block has type `unsafe -extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R`, where `'l1`, ... `'lm` -are its lifetime parameters, `A1`, ..., `An` are the declared types of its -parameters and `R` is the declared return type. +A function declared with an explicit safety qualifier (`unsafe`, `safe`) would +take such safety qualification, if no qualifier is present is implicitly +`unsafe`. When coerced to a function pointer, a function declared in an extern +block has type `unsafe extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R`, +where `'l1`, ... `'lm` are its lifetime parameters, `A1`, ..., `An` are the +declared types of its parameters and `R` is the declared return type. ## Statics Statics within external blocks are declared in the same way as [statics] outside of external blocks, except that they do not have an expression initializing their value. -It is `unsafe` to access a static item declared in an extern block, whether or -not it's mutable, because there is nothing guaranteeing that the bit pattern at the static's -memory is valid for the type it is declared with, since some arbitrary (e.g. C) code is in charge -of initializing the static. +It is `unsafe` by default or if the item is declared as `unsafe` to access a static item declared in +an extern block, unless the item was explicitly declared as `safe`. +It does not matter if it's mutable, because there is nothing guaranteeing that the bit pattern at +the static's memory is valid for the type it is declared with, since some arbitrary (e.g. C) code is +in charge of initializing the static. Extern statics can be either immutable or mutable just like [statics] outside of external blocks. An immutable static *must* be initialized before any Rust code is executed. It is not enough for @@ -69,34 +70,34 @@ standard C ABI on the specific platform. Other ABIs may be specified using an ```rust // Interface to the Windows API -extern "stdcall" { } +unsafe extern "stdcall" { } ``` There are three ABI strings which are cross-platform, and which all compilers are guaranteed to support: -* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any +* `unsafe extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any Rust code. -* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default +* `unsafe extern "C"` -- This is the same as `extern fn foo()`; whatever the default your C compiler supports. -* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in +* `unsafe extern "system"` -- Usually the same as `extern "C"`, except on Win32, in which case it's `"stdcall"`, or what you should use to link to the Windows API itself There are also some platform-specific ABI strings: -* `extern "cdecl"` -- The default for x86\_32 C code. -* `extern "stdcall"` -- The default for the Win32 API on x86\_32. -* `extern "win64"` -- The default for C code on x86\_64 Windows. -* `extern "sysv64"` -- The default for C code on non-Windows x86\_64. -* `extern "aapcs"` -- The default for ARM. -* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's +* `unsafe extern "cdecl"` -- The default for x86\_32 C code. +* `unsafe extern "stdcall"` -- The default for the Win32 API on x86\_32. +* `unsafe extern "win64"` -- The default for C code on x86\_64 Windows. +* `unsafe extern "sysv64"` -- The default for C code on non-Windows x86\_64. +* `unsafe extern "aapcs"` -- The default for ARM. +* `unsafe extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's `__fastcall` and GCC and clang's `__attribute__((fastcall))` -* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's +* `unsafe extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's `__vectorcall` and clang's `__attribute__((vectorcall))` -* `extern "thiscall"` -- The default for C++ member functions on MSVC -- corresponds to MSVC's +* `unsafe extern "thiscall"` -- The default for C++ member functions on MSVC -- corresponds to MSVC's `__thiscall` and GCC and clang's `__attribute__((thiscall))` -* `extern "efiapi"` -- The ABI used for [UEFI] functions. +* `unsafe extern "efiapi"` -- The ABI used for [UEFI] functions. ## Variadic functions @@ -105,7 +106,7 @@ last argument. The variadic parameter may optionally be specified with an identifier. ```rust -extern "C" { +unsafe extern "C" { fn foo(...); fn bar(x: i32, ...); fn with_name(format: *const u8, args: ...); @@ -152,17 +153,17 @@ not specified. ```rust,ignore #[link(name = "crypto")] -extern { +unsafe extern { // … } #[link(name = "CoreFoundation", kind = "framework")] -extern { +unsafe extern { // … } #[link(wasm_import_module = "foo")] -extern { +unsafe extern { // … } ``` @@ -277,7 +278,7 @@ block to indicate the symbol to import for the given function or static. It uses the [_MetaNameValueStr_] syntax to specify the name of the symbol. ```rust -extern { +unsafe extern { #[link_name = "actual_symbol_name"] fn name_in_rust(); } @@ -306,7 +307,7 @@ it, and that assigned ordinal may change between builds of the binary. ```rust,ignore #[link(name = "exporter", kind = "raw-dylib")] -extern "stdcall" { +unsafe extern "stdcall" { #[link_ordinal(15)] fn imported_function_stdcall(i: i32); } diff --git a/src/items/functions.md b/src/items/functions.md index ae698fb..4e00cac 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -157,7 +157,7 @@ their _definition_: ```rust,ignore -extern "ABI" { +unsafe extern "ABI" { fn foo(); /* no body */ } unsafe { foo() } diff --git a/src/types/never.md b/src/types/never.md index 3fbd2ad..8ed2248 100644 --- a/src/types/never.md +++ b/src/types/never.md @@ -17,7 +17,7 @@ fn foo() -> ! { ``` ```rust -extern "C" { +unsafe extern "C" { pub fn no_return_extern_func() -> !; } ``` From 94ecfacc3758a6ce399764ea7dc4c285aedfdbf8 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 21 Jul 2024 08:55:51 +0000 Subject: [PATCH 004/189] Revise changes for `unsafe extern` blocks We made an editing pass on the changes for `unsafe extern` blocks. We fixed some editorial items and aligned some stylistic points with the rest of the Reference. We did some rewording that also had the effect of minimizing the changes a bit further. In the examples, we added `safe` and `unsafe` qualifiers to items, as the RFC suggests that this is the preferred way to write these. --- src/items/external-blocks.md | 43 ++++++++++++++++++------------------ src/items/functions.md | 6 +++-- src/types/never.md | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 937cd92..85fe22b 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -23,38 +23,39 @@ blocks is only allowed in an `unsafe` context. The external block defines its functions and statics in the [value namespace] of the module or block where it is located. -Starting in edition 2024, the `unsafe` keyword is required to appear before the -`extern` keyword. In previous editions is accepted but not required. +**Edition differences**: Starting in the 2024 edition, the `unsafe` keyword is +required to appear before the `extern` keyword on external blocks. In previous +editions, it is accepted but not required. ## Functions Functions within external blocks are declared in the same way as other Rust functions, with the exception that they must not have a body and are instead terminated by a semicolon. Patterns are not allowed in parameters, only -[IDENTIFIER] or `_` may be used. Only safety funcion qualifiers are allowed -(`unsafe`, `safe`), other function qualifiers (`const`, `async`, and `extern`) -are not allowed. +[IDENTIFIER] or `_` may be used. The `safe` and `unsafe` function qualifiers are +allowed, but other function qualifiers (e.g. `const`, `async`, `extern`) are +not. Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler automatically translates between the Rust ABI and the foreign ABI. -A function declared with an explicit safety qualifier (`unsafe`, `safe`) would -take such safety qualification, if no qualifier is present is implicitly -`unsafe`. When coerced to a function pointer, a function declared in an extern -block has type `unsafe extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R`, -where `'l1`, ... `'lm` are its lifetime parameters, `A1`, ..., `An` are the -declared types of its parameters and `R` is the declared return type. +A function declared in an extern block is implicitly `unsafe` unless the `safe` +function qualifier is present. + +When coerced to a function pointer, a function declared in an extern block has +type `extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R`, where `'l1`, +... `'lm` are its lifetime parameters, `A1`, ..., `An` are the declared types of +its parameters, `R` is the declared return type. ## Statics Statics within external blocks are declared in the same way as [statics] outside of external blocks, except that they do not have an expression initializing their value. -It is `unsafe` by default or if the item is declared as `unsafe` to access a static item declared in -an extern block, unless the item was explicitly declared as `safe`. -It does not matter if it's mutable, because there is nothing guaranteeing that the bit pattern at -the static's memory is valid for the type it is declared with, since some arbitrary (e.g. C) code is -in charge of initializing the static. +Unless a static item declared in an extern block is qualified as `safe`, it is `unsafe` to access that item, whether or +not it's mutable, because there is nothing guaranteeing that the bit pattern at the static's +memory is valid for the type it is declared with, since some arbitrary (e.g. C) code is in charge +of initializing the static. Extern statics can be either immutable or mutable just like [statics] outside of external blocks. An immutable static *must* be initialized before any Rust code is executed. It is not enough for @@ -107,9 +108,9 @@ identifier. ```rust unsafe extern "C" { - fn foo(...); - fn bar(x: i32, ...); - fn with_name(format: *const u8, args: ...); + safe fn foo(...); + unsafe fn bar(x: i32, ...); + unsafe fn with_name(format: *const u8, args: ...); } ``` @@ -280,7 +281,7 @@ uses the [_MetaNameValueStr_] syntax to specify the name of the symbol. ```rust unsafe extern { #[link_name = "actual_symbol_name"] - fn name_in_rust(); + safe fn name_in_rust(); } ``` @@ -309,7 +310,7 @@ it, and that assigned ordinal may change between builds of the binary. #[link(name = "exporter", kind = "raw-dylib")] unsafe extern "stdcall" { #[link_ordinal(15)] - fn imported_function_stdcall(i: i32); + safe fn imported_function_stdcall(i: i32); } ``` diff --git a/src/items/functions.md b/src/items/functions.md index 4e00cac..77d9510 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -158,9 +158,11 @@ their _definition_: ```rust,ignore unsafe extern "ABI" { - fn foo(); /* no body */ + unsafe fn foo(); /* no body */ + safe fn bar(); /* no body */ } -unsafe { foo() } +unsafe { foo() }; +bar(); ``` When `"extern" Abi?*` is omitted from `FunctionQualifiers` in function items, diff --git a/src/types/never.md b/src/types/never.md index 8ed2248..7f58a3a 100644 --- a/src/types/never.md +++ b/src/types/never.md @@ -18,6 +18,6 @@ fn foo() -> ! { ```rust unsafe extern "C" { - pub fn no_return_extern_func() -> !; + pub safe fn no_return_extern_func() -> !; } ``` From 57a5f29b749adba17f4082b72b410eeb0614f877 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 21 Jul 2024 09:54:22 +0000 Subject: [PATCH 005/189] Add missing changes to the grammar Unsafe extern blocks imply some changes to the grammar. Let's make those and note the edition differences. --- src/items/external-blocks.md | 8 ++++++-- src/items/functions.md | 9 ++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 85fe22b..ba36263 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -2,7 +2,7 @@ > **Syntax**\ > _ExternBlock_ :\ ->    `unsafe`? `extern` [_Abi_]? `{`\ +>    `unsafe`[^unsafe-2024] `extern` [_Abi_]? `{`\ >       [_InnerAttribute_]\*\ >       _ExternalItem_\*\ >    `}` @@ -10,8 +10,12 @@ > _ExternalItem_ :\ >    [_OuterAttribute_]\* (\ >          [_MacroInvocationSemi_]\ ->       | ( [_Visibility_]? ( [_StaticItem_] | [_Function_] ) )\ +>       | ( [_Visibility_]? ( (`safe` | `unsafe`)?[^static-qualifiers] [_StaticItem_] | [_Function_] ) )\ >    ) +> +> [^unsafe-2024]: Prior to the 2024 edition, the `unsafe` keyword is optional. +> +> [^static-qualifiers]: *Relevant to editions earlier than Rust 2024*: The `safe` or `unsafe` qualifier is only allowed when the `extern` is qualified as `unsafe`. External blocks provide _declarations_ of items that are not _defined_ in the current crate and are the basis of Rust's foreign function interface. These are diff --git a/src/items/functions.md b/src/items/functions.md index 77d9510..8650292 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -8,7 +8,7 @@ >       ( [_BlockExpression_] | `;` ) > > _FunctionQualifiers_ :\ ->    `const`? `async`[^async-edition]? `unsafe`? (`extern` _Abi_?)? +>    `const`? `async`[^async-edition]? (`safe`[^extern-safe] | `unsafe`)?[^extern-qualifiers] (`extern` _Abi_?)? > > _Abi_ :\ >    [STRING_LITERAL] | [RAW_STRING_LITERAL] @@ -39,6 +39,13 @@ > > [^async-edition]: The `async` qualifier is not allowed in the 2015 edition. > +> [^extern-safe]: The `safe` function qualifier is only allowed within +> `extern` blocks. +> +> [^extern-qualifiers]: *Relevant to editions earlier than Rust 2024*: Within +> `extern` blocks, the `safe` or `unsafe` function qualifier is only allowed +> when the `extern` is qualified as `unsafe`. +> > [^fn-param-2015]: Function parameters with only a type are only allowed > in an associated function of a [trait item] in the 2015 edition. From 44db9e3b72a60e5ac58fdd2b6361138e67dca3f4 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 22 Jul 2024 08:29:49 +0000 Subject: [PATCH 006/189] Describe unsafe extern blocks in unsafety chapter Let's add a description of unsafe extern blocks to the chapter about unsafety. --- src/unsafe-keyword.md | 12 ++++++++++-- src/unsafety.md | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index a29fc94..63bc138 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -1,10 +1,10 @@ # The `unsafe` keyword The `unsafe` keyword can occur in several different contexts: -unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), and unsafe trait implementations (`unsafe impl`). +unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), unsafe trait implementations (`unsafe impl`), and unsafe external blocks (`unsafe extern`). It plays several different roles, depending on where it is used and whether the `unsafe_op_in_unsafe_fn` lint is enabled: - it is used to mark code that *defines* extra safety conditions (`unsafe fn`, `unsafe trait`) -- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`]) +- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`], `unsafe extern`) The following discusses each of these cases. See the [keyword documentation][keyword] for some illustrative examples. @@ -56,3 +56,11 @@ Unsafe trait implementations are the logical dual to unsafe traits: where unsafe [keyword]: ../std/keyword.unsafe.html [`get_unchecked`]: ../std/primitive.slice.html#method.get_unchecked [`unsafe_op_in_unsafe_fn`]: ../rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn + +## Unsafe external blocks (`unsafe extern`) + +The programmer who declares an [external block] must assure that the signatures of the items contained within are correct. Failing to do so may lead to undefined behavior. That this obligation has been met is indicated by writing `unsafe extern`. + +**Edition differences**: Prior to edition 2024, `extern` blocks were allowed without being qualified as `unsafe`. + +[external block]: items/external-blocks.md diff --git a/src/unsafety.md b/src/unsafety.md index 915fa5b..2330edd 100644 --- a/src/unsafety.md +++ b/src/unsafety.md @@ -11,7 +11,11 @@ Rust: - Accessing a field of a [`union`], other than to assign to it. - Calling an unsafe function (including an intrinsic or foreign function). - Implementing an [unsafe trait]. +- Declaring an [`extern`] block[^extern-2024]. +[^extern-2024]: Prior to the 2024 edition, extern blocks were allowed to be declared without `unsafe`. + +[`extern`]: items/external-blocks.md [`union`]: items/unions.md [mutable]: items/static-items.md#mutable-statics [external]: items/external-blocks.md From e35748b35872defc482d149c5bb2a4d1ff973acb Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 23 Jul 2024 13:56:30 -0700 Subject: [PATCH 007/189] Add the `safe` weak keyword. --- src/keywords.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keywords.md b/src/keywords.md index 46da9f1..c6472a3 100644 --- a/src/keywords.md +++ b/src/keywords.md @@ -118,6 +118,7 @@ is possible to declare a variable or method with the name `union`. > > **Lexer 2015**\ > KW_DYN : `dyn` +* `safe` is used for functions and statics, which has meaning in [external blocks]. [items]: items.md [Variables]: variables.md @@ -132,3 +133,4 @@ is possible to declare a variable or method with the name `union`. [`dyn`]: types/trait-object.md [loop label]: expressions/loop-expr.md#loop-labels [generic lifetime parameter]: items/generics.md +[external blocks]: items/external-blocks.md From f9171fa058b3b619227663d1330c6c4fee55ef79 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 23 Jul 2024 14:01:17 -0700 Subject: [PATCH 008/189] Add back the `?` for `unsafe` in extern blocks. The grammar is intended to show the AST before validation. This is the grammar accepted by macros, for example. --- src/items/external-blocks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index ba36263..d65e924 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -2,7 +2,7 @@ > **Syntax**\ > _ExternBlock_ :\ ->    `unsafe`[^unsafe-2024] `extern` [_Abi_]? `{`\ +>    `unsafe`?[^unsafe-2024] `extern` [_Abi_]? `{`\ >       [_InnerAttribute_]\*\ >       _ExternalItem_\*\ >    `}` @@ -13,7 +13,7 @@ >       | ( [_Visibility_]? ( (`safe` | `unsafe`)?[^static-qualifiers] [_StaticItem_] | [_Function_] ) )\ >    ) > -> [^unsafe-2024]: Prior to the 2024 edition, the `unsafe` keyword is optional. +> [^unsafe-2024]: Starting with the 2024 Edition, the `unsafe` keyword is required semantically. > > [^static-qualifiers]: *Relevant to editions earlier than Rust 2024*: The `safe` or `unsafe` qualifier is only allowed when the `extern` is qualified as `unsafe`. From 78033527d6eab9e1b8f71201bfba0561ef25995b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 24 Jul 2024 16:42:09 -0700 Subject: [PATCH 009/189] Update extern block grammar to be before validation. The grammar in the reference defines the grammar before ast validation, since that is the grammar accepted by macros. Any restrictions imposed by validation are described in prose (using the term "semantically", but I don't feel like that is the greatest term to use). --- src/items/external-blocks.md | 4 +--- src/items/functions.md | 10 ++++++++-- src/items/static-items.md | 8 +++++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index d65e924..6f7d883 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -10,12 +10,10 @@ > _ExternalItem_ :\ >    [_OuterAttribute_]\* (\ >          [_MacroInvocationSemi_]\ ->       | ( [_Visibility_]? ( (`safe` | `unsafe`)?[^static-qualifiers] [_StaticItem_] | [_Function_] ) )\ +>       | ( [_Visibility_]? ( [_StaticItem_] | [_Function_] ) )\ >    ) > > [^unsafe-2024]: Starting with the 2024 Edition, the `unsafe` keyword is required semantically. -> -> [^static-qualifiers]: *Relevant to editions earlier than Rust 2024*: The `safe` or `unsafe` qualifier is only allowed when the `extern` is qualified as `unsafe`. External blocks provide _declarations_ of items that are not _defined_ in the current crate and are the basis of Rust's foreign function interface. These are diff --git a/src/items/functions.md b/src/items/functions.md index 8650292..af4fc7b 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -8,7 +8,10 @@ >       ( [_BlockExpression_] | `;` ) > > _FunctionQualifiers_ :\ ->    `const`? `async`[^async-edition]? (`safe`[^extern-safe] | `unsafe`)?[^extern-qualifiers] (`extern` _Abi_?)? +>    `const`? `async`[^async-edition]? _ItemSafety_?[^extern-qualifiers] (`extern` _Abi_?)? +> +> _ItemSafety_ :\ +>    `safe`[^extern-safe] | `unsafe` > > _Abi_ :\ >    [STRING_LITERAL] | [RAW_STRING_LITERAL] @@ -39,7 +42,7 @@ > > [^async-edition]: The `async` qualifier is not allowed in the 2015 edition. > -> [^extern-safe]: The `safe` function qualifier is only allowed within +> [^extern-safe]: The `safe` function qualifier is only allowed semantically within > `extern` blocks. > > [^extern-qualifiers]: *Relevant to editions earlier than Rust 2024*: Within @@ -65,6 +68,8 @@ fn answer_to_life_the_universe_and_everything() -> i32 { } ``` +The `safe` function is semantically only allowed when used in an [`extern` block]. + ## Function parameters Function parameters are irrefutable [patterns], so any pattern that is valid in @@ -424,3 +429,4 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [implementation]: implementations.md [value namespace]: ../names/namespaces.md [variadic function]: external-blocks.md#variadic-functions +[`extern` block]: external-blocks.md diff --git a/src/items/static-items.md b/src/items/static-items.md index 343d30c..f00f1aa 100644 --- a/src/items/static-items.md +++ b/src/items/static-items.md @@ -2,8 +2,11 @@ > **Syntax**\ > _StaticItem_ :\ ->    `static` `mut`? [IDENTIFIER] `:` [_Type_] +>    [_ItemSafety_]?[^extern-safety] `static` `mut`? [IDENTIFIER] `:` [_Type_] > ( `=` [_Expression_] )? `;` +> +> [^extern-safety]: The `safe` and `unsafe` function qualifiers are only +> allowed semantically within `extern` blocks. A *static item* is similar to a [constant], except that it represents a precise memory location in the program. All references to the static refer to the same @@ -28,6 +31,8 @@ statics: The initializer expression must be omitted in an [external block], and must be provided for free static items. +The `safe` and `unsafe` qualifiers are semantically only allowed when used in an [external block]. + ## Statics & generics A static item defined in a generic scope (for example in a blanket or default @@ -139,3 +144,4 @@ following are true: [_Type_]: ../types.md#type-expressions [_Expression_]: ../expressions.md [value namespace]: ../names/namespaces.md +[_ItemSafety_]: functions.md From f8f1e439df46d4b819311f907f15d36c635ee7ac Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 24 Jul 2024 16:43:18 -0700 Subject: [PATCH 010/189] Add clarity about `safe` and `unsafe` edition difference. The `safe` and `unsafe` item qualifiers can only be used if `unsafe` is used (pre-2024). I didn't see this specified elsewhere. --- 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 6f7d883..3af2a67 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -27,7 +27,8 @@ The external block defines its functions and statics in the [value namespace] of **Edition differences**: Starting in the 2024 edition, the `unsafe` keyword is required to appear before the `extern` keyword on external blocks. In previous -editions, it is accepted but not required. +editions, it is accepted but not required. The `safe` and `unsafe` item qualifiers +are only allowed if the external block itself is marked as `unsafe`. ## Functions From eb1d4a701221501d6d6fa2999a679f8d9440c9c8 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:14:26 -0400 Subject: [PATCH 011/189] Add identifiers to comments.md --- src/comments.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/comments.md b/src/comments.md index 795bf63..753051f 100644 --- a/src/comments.md +++ b/src/comments.md @@ -1,5 +1,8 @@ # Comments + +r[comments.lexical] + > **Lexer**\ > LINE_COMMENT :\ >       `//` (~\[`/` `!` `\n`] | `//`) ~`\n`\*\ @@ -34,25 +37,39 @@ ## Non-doc comments +r[comments.normal] + Comments follow the general C++ style of line (`//`) and block (`/* ... */`) comment forms. Nested block comments are supported. +r[comments.normal.tokenization] Non-doc comments are interpreted as a form of whitespace. ## Doc comments +r[comments.doc] + +r[comments.doc.syntax] Line doc comments beginning with exactly _three_ slashes (`///`), and block doc comments (`/** ... */`), both outer doc comments, are interpreted as a -special syntax for [`doc` attributes]. That is, they are equivalent to writing +special syntax for [`doc` attributes]. + +r[comments.doc.attribute] +That is, they are equivalent to writing `#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into `#[doc="Foo"]` and `/** Bar */` turns into `#[doc="Bar"]`. +r[comments.doc.inner-syntax] Line comments beginning with `//!` and block comments `/*! ... */` are doc comments that apply to the parent of the comment, rather than the item -that follows. That is, they are equivalent to writing `#![doc="..."]` around +that follows. + +r[comments.doc.inner-attribute] +That is, they are equivalent to writing `#![doc="..."]` around the body of the comment. `//!` comments are usually used to document modules that occupy a source file. +r[comments.doc.bare-cr] The character `U+000D` (CR) is not allowed in doc comments. > **Note**: The sequence `U+000D` (CR) immediately followed by `U+000A` (LF) would have been previously transformed into a single `U+000A` (LF). From 92b8f14c8f664cc5d31c620e107f5c25c0e5d195 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 9 Aug 2024 15:30:05 -0700 Subject: [PATCH 012/189] Remove 2024 unsafe extern block notes These will be added back when 2024 stabilizes. --- src/items/external-blocks.md | 9 +-------- src/items/functions.md | 6 +----- src/unsafe-keyword.md | 2 -- src/unsafety.md | 4 +--- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 3af2a67..bb59af8 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -2,7 +2,7 @@ > **Syntax**\ > _ExternBlock_ :\ ->    `unsafe`?[^unsafe-2024] `extern` [_Abi_]? `{`\ +>    `unsafe`? `extern` [_Abi_]? `{`\ >       [_InnerAttribute_]\*\ >       _ExternalItem_\*\ >    `}` @@ -12,8 +12,6 @@ >          [_MacroInvocationSemi_]\ >       | ( [_Visibility_]? ( [_StaticItem_] | [_Function_] ) )\ >    ) -> -> [^unsafe-2024]: Starting with the 2024 Edition, the `unsafe` keyword is required semantically. External blocks provide _declarations_ of items that are not _defined_ in the current crate and are the basis of Rust's foreign function interface. These are @@ -25,11 +23,6 @@ blocks is only allowed in an `unsafe` context. The external block defines its functions and statics in the [value namespace] of the module or block where it is located. -**Edition differences**: Starting in the 2024 edition, the `unsafe` keyword is -required to appear before the `extern` keyword on external blocks. In previous -editions, it is accepted but not required. The `safe` and `unsafe` item qualifiers -are only allowed if the external block itself is marked as `unsafe`. - ## Functions Functions within external blocks are declared in the same way as other Rust diff --git a/src/items/functions.md b/src/items/functions.md index af4fc7b..54988df 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -8,7 +8,7 @@ >       ( [_BlockExpression_] | `;` ) > > _FunctionQualifiers_ :\ ->    `const`? `async`[^async-edition]? _ItemSafety_?[^extern-qualifiers] (`extern` _Abi_?)? +>    `const`? `async`[^async-edition]? _ItemSafety_? (`extern` _Abi_?)? > > _ItemSafety_ :\ >    `safe`[^extern-safe] | `unsafe` @@ -45,10 +45,6 @@ > [^extern-safe]: The `safe` function qualifier is only allowed semantically within > `extern` blocks. > -> [^extern-qualifiers]: *Relevant to editions earlier than Rust 2024*: Within -> `extern` blocks, the `safe` or `unsafe` function qualifier is only allowed -> when the `extern` is qualified as `unsafe`. -> > [^fn-param-2015]: Function parameters with only a type are only allowed > in an associated function of a [trait item] in the 2015 edition. diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index 63bc138..df68a74 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -61,6 +61,4 @@ Unsafe trait implementations are the logical dual to unsafe traits: where unsafe The programmer who declares an [external block] must assure that the signatures of the items contained within are correct. Failing to do so may lead to undefined behavior. That this obligation has been met is indicated by writing `unsafe extern`. -**Edition differences**: Prior to edition 2024, `extern` blocks were allowed without being qualified as `unsafe`. - [external block]: items/external-blocks.md diff --git a/src/unsafety.md b/src/unsafety.md index 2330edd..237a4bf 100644 --- a/src/unsafety.md +++ b/src/unsafety.md @@ -11,9 +11,7 @@ Rust: - Accessing a field of a [`union`], other than to assign to it. - Calling an unsafe function (including an intrinsic or foreign function). - Implementing an [unsafe trait]. -- Declaring an [`extern`] block[^extern-2024]. - -[^extern-2024]: Prior to the 2024 edition, extern blocks were allowed to be declared without `unsafe`. +- Declaring an [`extern`] block. [`extern`]: items/external-blocks.md [`union`]: items/unions.md From fb8201a5fe0007bc06c8b4a9320902c2bd4f7c98 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 10 Aug 2024 13:32:32 +0200 Subject: [PATCH 013/189] const_eval: update for const-fn float stabilization --- src/const_eval.md | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/const_eval.md b/src/const_eval.md index af8d486..a494b5c 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -61,12 +61,15 @@ A _const context_ is one of the following: * A [const generic argument] * A [const block] +Const contexts that are used as parts of types (array type and repeat length +expressions as well as const generic arguments) can only make restricted use of +surrounding generic type and lifetime parameters. + ## Const Functions A _const fn_ is a function that one is permitted to call from a const context. Declaring a function `const` has no effect on any existing uses, it only restricts the types that arguments and the -return type may use, as well as prevent various expressions from being used within it. You can freely -do anything with a const function that you can do with a regular function. +return type may use, and restricts the function body to constant expressions. When called from a const context, the function is interpreted by the compiler at compile time. The interpretation happens in the @@ -74,27 +77,6 @@ environment of the compilation target and not the host. So `usize` is `32` bits if you are compiling against a `32` bit system, irrelevant of whether you are building on a `64` bit or a `32` bit system. -Const functions have various restrictions to make sure that they can be -evaluated at compile-time. It is, for example, not possible to write a random -number generator as a const function. Calling a const function at compile-time -will always yield the same result as calling it at runtime, even when called -multiple times. There's one exception to this rule: if you are doing complex -floating point operations in extreme situations, then you might get (very -slightly) different results. It is advisable to not make array lengths and enum -discriminants depend on floating point computations. - - -Notable features that are allowed in const contexts but not in const functions include: - -* floating point operations - * floating point values are treated just like generic parameters without trait bounds beyond - `Copy`. So you cannot do anything with them but copy/move them around. - -Conversely, the following are possible in a const function, but not in a const context: - -* Use of generic type and lifetime parameters. - * Const contexts do allow limited use of [const generic parameters]. - [arithmetic]: expressions/operator-expr.md#arithmetic-and-logical-binary-operators [array expressions]: expressions/array-expr.md [array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions From 99008e05e6ab6e0076769f6498fd602aef93654e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 12 Aug 2024 20:13:57 -0400 Subject: [PATCH 014/189] Tweak repr(transparent) --- src/type-layout.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index c53e9d0..4f7575f 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -585,12 +585,11 @@ was wrapped in a newtype `struct` with the same `align` modifier. The `transparent` representation can only be used on a [`struct`][structs] or an [`enum`][enumerations] with a single variant that has: - -- a single field with non-zero size, and -- any number of fields with size 0 and alignment 1 (e.g. [`PhantomData`]). +- any number of fields with size 0 and alignment 1 (e.g. [`PhantomData`]), and +- at most one other field. Structs and enums with this representation have the same layout and ABI -as the single non-zero sized field. +as the only non-size 0 non-alignment 1 field, if present, or unit otherwise. This is different than the `C` representation because a struct with the `C` representation will always have the ABI of a `C` `struct` From 081c66d5f19e0e8f137f52a678b8307b73af0cf5 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 13 Aug 2024 15:02:51 -0400 Subject: [PATCH 015/189] Add spec identifier syntax to destructors.md --- src/destructors.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/destructors.md b/src/destructors.md index 9c42642..8e4873a 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -1,11 +1,15 @@ # Destructors +r[destructors] + +r[destructors.general] When an [initialized] [variable] or [temporary] goes out of [scope](#drop-scopes), its *destructor* is run, or it is *dropped*. [Assignment] also runs the destructor of its left-hand operand, if it's initialized. If a variable has been partially initialized, only its initialized fields are dropped. +r[destructors.operation] The destructor of a type `T` consists of: 1. If `T: Drop`, calling [`::drop`] @@ -20,6 +24,7 @@ The destructor of a type `T` consists of: * [Trait objects] run the destructor of the underlying type. * Other types don't result in any further drops. +r[destructors.drop_in_place] If a destructor must be run manually, such as when implementing your own smart pointer, [`std::ptr::drop_in_place`] can be used. @@ -57,48 +62,85 @@ core::mem::forget(partial_move.1); ## Drop scopes +r[destructor.scope] + + +r[destructor.scope.general] Each variable or temporary is associated to a *drop scope*. When control flow leaves a drop scope all variables associated to that scope are dropped in reverse order of declaration (for variables) or creation (for temporaries). +r[destructor.scope.desugaring] Drop scopes are determined after replacing [`for`], [`if let`], and [`while let`] expressions with the equivalent expressions using [`match`]. + +r[destructor.scope.operators] Overloaded operators are not distinguished from built-in operators and [binding modes] are not considered. +r[destructor.scope.list] Given a function, or closure, there are drop scopes for: +r[destructor.scope.function] * The entire function + +r[destructor.scope.statement] * Each [statement] + +r[destructor.scope.expression] * Each [expression] + +r[destructor.scope.block] * Each block, including the function body * In the case of a [block expression], the scope for the block and the expression are the same scope. + +r[destructor.scope.match-arm] * Each arm of a `match` expression +r[destructor.scope.nesting] Drop scopes are nested within one another as follows. When multiple scopes are left at once, such as when returning from a function, variables are dropped from the inside outwards. +r[destructor.scope.nesting.function] * The entire function scope is the outer most scope. + +r[destructor.scope.nesting.function-body] * The function body block is contained within the scope of the entire function. + +r[destructor.scope.nesting.expr-statement] * The parent of the expression in an expression statement is the scope of the statement. + +r[destructor.scope.nesting.let-initializer] * The parent of the initializer of a [`let` statement] is the `let` statement's scope. + +r[destructor.scope.nesting.statement] * The parent of a statement scope is the scope of the block that contains the statement. + +r[destructor.scope.nesting.match-guard] * The parent of the expression for a `match` guard is the scope of the arm that the guard is for. + +r[destructor.scope.nesting.match-arm] * The parent of the expression after the `=>` in a `match` expression is the scope of the arm that it's in. + +r[destructor.scope.nesting.match] * The parent of the arm scope is the scope of the `match` expression that it belongs to. + +r[destructor.scope.nesting.other] * The parent of all other scopes is the scope of the immediately enclosing expression. ### Scopes of function parameters +r[destructors.scope.params] + All function parameters are in the scope of the entire function body, so are dropped last when evaluating the function. Each actual function parameter is dropped after any bindings introduced in that parameter's pattern. @@ -125,6 +167,9 @@ patterns_in_parameters( ### Scopes of local variables +r[destructor.scope.bindings] + +r[destructor.scope.bindings.general] Local variables declared in a `let` statement are associated to the scope of the block that contains the `let` statement. Local variables declared in a `match` expression are associated to the arm scope of the `match` arm that they @@ -144,15 +189,21 @@ let declared_first = PrintOnDrop("Dropped last in outer scope"); let declared_last = PrintOnDrop("Dropped first in outer scope"); ``` +r[destructors.scope.bindings.match-pattern-order] If multiple patterns are used in the same arm for a `match` expression, then an unspecified pattern will be used to determine the drop order. ### Temporary scopes +r[destructors.scope.temporary] + + +r[destructor.scope.temporary.general] The *temporary scope* of an expression is the scope that is used for the temporary variable that holds the result of that expression when used in a [place context], unless it is [promoted]. +r[destructor.scope.temporary.enclosing] Apart from lifetime extension, the temporary scope of an expression is the smallest scope that contains the expression and is one of the following: @@ -215,6 +266,8 @@ match PrintOnDrop("Matched value in final expression") { ### Operands +r[destructors.scope.operands] + Temporaries are also created to hold the result of operands to an expression while the other operands are evaluated. The temporaries are associated to the scope of the expression with that operand. Since the temporaries are moved from @@ -245,6 +298,8 @@ loop { ### Constant promotion +r[destructors.scope.const-promotion] + Promotion of a value expression to a `'static` slot occurs when the expression could be written in a constant and borrowed, and that borrow could be dereferenced where @@ -256,9 +311,13 @@ always has the type `&'static Option<_>`, as it contains nothing disallowed). ### Temporary lifetime extension +r[destructors.scope.lifetime-extension] + > **Note**: The exact rules for temporary lifetime extension are subject to > change. This is describing the current behavior only. +r[destructors.scope.lifetime-extension.let] + The temporary scopes for expressions in `let` statements are sometimes *extended* to the scope of the block containing the `let` statement. This is done when the usual temporary scope would be too small, based on certain @@ -271,6 +330,7 @@ let x = &mut 0; println!("{}", x); ``` +r[destructors.scope.lifetime-extension.sub-expressions] If a [borrow][borrow expression], [dereference][dereference expression], [field][field expression], or [tuple indexing expression] has an extended temporary scope then so does its operand. If an [indexing expression] has an @@ -279,6 +339,10 @@ temporary scope. #### Extending based on patterns +r[destructors.scope.lifetime-extension.patterns] + + +r[destructors.scope.lifetime-extension.patterns.extending] An *extending pattern* is either * An [identifier pattern] that binds by reference or mutable reference. @@ -289,11 +353,14 @@ An *extending pattern* is either So `ref x`, `V(ref x)` and `[ref x, y]` are all extending patterns, but `x`, `&ref x` and `&(ref x,)` are not. +r[destructors.scope.lifetime-extension.patterns.let] If the pattern in a `let` statement is an extending pattern then the temporary scope of the initializer expression is extended. #### Extending based on expressions +r[destructors.scope.lifetime-extension.exprs] + For a let statement with an initializer, an *extending expression* is an expression which is one of the following: @@ -346,6 +413,8 @@ let x = (&temp()).use_temp(); // ERROR ## Not running destructors +r[destructors.forget] + [`std::mem::forget`] can be used to prevent the destructor of a variable from being run, and [`std::mem::ManuallyDrop`] provides a wrapper to prevent a variable or field from being dropped automatically. From 59a8f39b0e0949412175c334ee10a33ea4e7d1ec Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 14 Aug 2024 13:39:37 -0500 Subject: [PATCH 016/189] Typo: 'a' to 'an' in type-coercions.md --- src/type-coercions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type-coercions.md b/src/type-coercions.md index 2bdbb53..f1016b1 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -180,7 +180,7 @@ an implementation of `Unsize` for `T` will be provided: * T is not part of the type of any other fields. Additionally, a type `Foo` can implement `CoerceUnsized>` when `T` -implements `Unsize` or `CoerceUnsized>`. This allows it to provide a +implements `Unsize` or `CoerceUnsized>`. This allows it to provide an unsized coercion to `Foo`. > Note: While the definition of the unsized coercions and their implementation From 08737a2328788c6d9ac2c90db97408f888daaa7f Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 2 Aug 2024 20:49:40 +0200 Subject: [PATCH 017/189] add the `const` operand to docs for inline assembly --- src/inline-assembly.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 1167fa3..960fff1 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -54,7 +54,7 @@ format_string := STRING_LITERAL / RAW_STRING_LITERAL dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout" reg_spec := / "\"" "\"" operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" -reg_operand := [ident "="] dir_spec "(" reg_spec ")" operand_expr +reg_operand := [ident "="] dir_spec "(" reg_spec ")" operand_expr / sym / const clobber_abi := "clobber_abi(" *("," ) [","] ")" option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" options := "options(" option *("," option) [","] ")" @@ -174,6 +174,10 @@ r[asm.operand-type.supported-operands.sym] - A mangled symbol name referring to the item is substituted into the asm template string. - The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc). - `` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data. +* `const ` + - `` must be an integer constant expression. This expression follows the same rules as inline `const` blocks. + - The type of the expression may be any integer type, but defaults to `i32` just like integer literals. + - The value of the expression is formatted as a string and substituted directly into the asm template string. r[asm.operand-type.left-to-right] Operand expressions are evaluated from left to right, just like function call arguments. @@ -181,7 +185,7 @@ After the `asm!` has executed, outputs are written to in left to right order. This is significant if two outputs point to the same place: that place will contain the value of the rightmost output. r[asm.operand-type.global_asm-restriction] -Since `global_asm!` exists outside a function, it can only use `sym` operands. +Since `global_asm!` exists outside a function, it can only use `sym` and `const` operands. ## Register operands From 4ec434aaeb098023fefaf96c35f007c854bda7ba Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 15 Aug 2024 11:32:16 +0200 Subject: [PATCH 018/189] don't capitalize Undefined Behavior --- src/behavior-considered-undefined.md | 2 +- src/expressions/operator-expr.md | 4 ++-- src/types/textual.md | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index bee5010..69c44bc 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -101,7 +101,7 @@ alignment 1). In other words, the alignment requirement derives from the type of the pointer that was dereferenced, *not* the type of the field that is being accessed. -Note that a place based on a misaligned pointer only leads to Undefined Behavior +Note that a place based on a misaligned pointer only leads to undefined behavior when it is loaded from or stored to. `addr_of!`/`addr_of_mut!` on such a place is allowed. `&`/`&mut` on a place requires the alignment of the field type (or else the program would be "producing an invalid value"), which generally is a diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index d3fa33b..cd9e5e1 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -100,7 +100,7 @@ struct Packed { } let packed = Packed { f1: 1, f2: 2 }; -// `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior! +// `&packed.f2` would create an unaligned reference, and thus be undefined behavior! let raw_f2 = ptr::addr_of!(packed.f2); assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); ``` @@ -116,7 +116,7 @@ struct Demo { let mut uninit = MaybeUninit::::uninit(); // `&uninit.as_mut().field` would create a reference to an uninitialized `bool`, -// and thus be Undefined Behavior! +// and thus be undefined behavior! let f1_ptr = unsafe { ptr::addr_of_mut!((*uninit.as_mut_ptr()).field) }; unsafe { f1_ptr.write(true); } let init = unsafe { uninit.assume_init() }; diff --git a/src/types/textual.md b/src/types/textual.md index fcbec08..a4765b5 100644 --- a/src/types/textual.md +++ b/src/types/textual.md @@ -4,7 +4,7 @@ The types `char` and `str` hold textual data. A value of type `char` is a [Unicode scalar value] (i.e. a code point that is not a surrogate), represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF -or 0xE000 to 0x10FFFF range. It is immediate [Undefined Behavior] to create a +or 0xE000 to 0x10FFFF range. It is immediate [undefined behavior] to create a `char` that falls outside this range. A `[char]` is effectively a UCS-4 / UTF-32 string of length 1. @@ -12,7 +12,7 @@ A value of type `str` is represented the same way as `[u8]`, a slice of 8-bit unsigned bytes. However, the Rust standard library makes extra assumptions about `str`: methods working on `str` assume and ensure that the data in there is valid UTF-8. Calling a `str` method with a non-UTF-8 buffer can cause -[Undefined Behavior] now or in the future. +[undefined behavior] now or in the future. Since `str` is a [dynamically sized type], it can only be instantiated through a pointer type, such as `&str`. @@ -26,5 +26,5 @@ Every byte of a `char` is guaranteed to be initialized (in other words, some bit patterns are invalid `char`s, the inverse is not always sound). [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -[Undefined Behavior]: ../behavior-considered-undefined.md +[undefined behavior]: ../behavior-considered-undefined.md [dynamically sized type]: ../dynamically-sized-types.md From 6f503eeaef1b7054703df993a5f556333faa277d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 17 Aug 2024 11:43:19 -0700 Subject: [PATCH 019/189] Rewrite std_links This rewrites std_links for two major changes: - Uses pulldown_cmark to parse the markdown instead of using regular expressions. The RegEx approach was just too unreliable. - Call rustdoc only once, instead of once per chapter. The overhead of calling rustdoc is significant, and calling it for each chapter was extremely slow. Unfortunately the error messages are a little worse now, since it doesn't show which chapter a bad link came from. I'm uncertain how to make that better. --- mdbook-spec/Cargo.lock | 1 + mdbook-spec/Cargo.toml | 2 + mdbook-spec/src/lib.rs | 5 +- mdbook-spec/src/std_links.rs | 358 +++++++++++++++++++++++------------ 4 files changed, 246 insertions(+), 120 deletions(-) diff --git a/mdbook-spec/Cargo.lock b/mdbook-spec/Cargo.lock index 1fc0efa..ff835b4 100644 --- a/mdbook-spec/Cargo.lock +++ b/mdbook-spec/Cargo.lock @@ -407,6 +407,7 @@ dependencies = [ "mdbook", "once_cell", "pathdiff", + "pulldown-cmark", "regex", "semver", "serde_json", diff --git a/mdbook-spec/Cargo.toml b/mdbook-spec/Cargo.toml index a81915d..703322c 100644 --- a/mdbook-spec/Cargo.toml +++ b/mdbook-spec/Cargo.toml @@ -13,6 +13,8 @@ anyhow = "1.0.79" mdbook = { version = "0.4.36", default-features = false } 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 } regex = "1.9.4" semver = "1.0.21" serde_json = "1.0.113" diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 6591e41..ef1d565 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -154,7 +154,6 @@ impl Preprocessor for Spec { } ch.content = self.rule_definitions(&ch, &mut found_rules); ch.content = self.admonitions(&ch); - ch.content = std_links::std_links(&ch); }); // This is a separate pass because it relies on the modifications of // the previous passes. @@ -167,6 +166,10 @@ impl Preprocessor for Spec { } ch.content = self.auto_link_references(&ch, &found_rules); }); + // Final pass will resolve everything as a std link (or error if the + // link is unknown). + std_links::std_links(&mut book); + Ok(book) } } diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index 0c7860b..789518c 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -1,145 +1,199 @@ +//! Support for translating links to the standard library. + +use mdbook::book::Book; use mdbook::book::Chapter; +use mdbook::BookItem; use once_cell::sync::Lazy; -use regex::{Captures, Regex}; -use std::collections::HashSet; +use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag}; +use regex::Regex; +use std::collections::HashMap; use std::fmt::Write as _; use std::fs; use std::io::{self, Write as _}; +use std::ops::Range; +use std::path::PathBuf; use std::process::{self, Command}; use tempfile::TempDir; -/// A markdown link (without the brackets) that might possibly be a link to -/// the standard library using rustdoc's intra-doc notation. -const STD_LINK: &str = r"(?: [a-z]+@ )? - (?: std|core|alloc|proc_macro|test ) - (?: ::[A-Za-z0-9_!,:<>{}()\[\]]+ )?"; - -/// The Regex for a markdown link that might be a link to the standard library. -static STD_LINK_RE: Lazy = Lazy::new(|| { - Regex::new(&format!( - r"(?x) - (?: - ( \[`[^`]+`\] ) \( ({STD_LINK}) \) - ) - | (?: - ( \[`{STD_LINK}`\] ) - ) - " - )) - .unwrap() -}); - /// The Regex used to extract the std links from the HTML generated by rustdoc. static STD_LINK_EXTRACT_RE: Lazy = - Lazy::new(|| Regex::new(r#"
  • ]*href="(https://doc.rust-lang.org/[^"]+)""#).unwrap()); - -/// The Regex for a markdown link definition. -static LINK_DEF_RE: Lazy = Lazy::new(|| { - // This is a pretty lousy regex for a link definition. It doesn't - // handle things like blockquotes, code blocks, etc. Using a - // markdown parser isn't really feasible here, it would be nice to - // improve this. - Regex::new(r#"(?m)^(?
  • LINK: (.*)
  • "#).unwrap()); + +/// The Regex used to extract the URL from an HTML link. +static ANCHOR_URL: Lazy = Lazy::new(|| Regex::new(" = Lazy::new(|| Regex::new(r"(?s)(\[.+\])(\(.+\))").unwrap()); +/// Regex for a markdown reference link, like `[foo][bar]`. +static MD_LINK_REFERENCE: Lazy = Lazy::new(|| Regex::new(r"(?s)(\[.+\])(\[.*\])").unwrap()); +/// Regex for a markdown shortcut link, like `[foo]`. +static MD_LINK_SHORTCUT: Lazy = Lazy::new(|| Regex::new(r"(?s)(\[.+\])").unwrap()); /// Converts links to the standard library to the online documentation in a /// fashion similar to rustdoc intra-doc links. -pub fn std_links(chapter: &Chapter) -> String { - let links = collect_markdown_links(chapter); - if links.is_empty() { - return chapter.content.clone(); +pub fn std_links(book: &mut Book) { + // Collect all links in all chapters. + let mut chapter_links = HashMap::new(); + for item in book.iter() { + let BookItem::Chapter(ch) = item else { + continue; + }; + if ch.is_draft_chapter() { + continue; + } + let key = ch.source_path.as_ref().unwrap(); + chapter_links.insert(key, collect_markdown_links(&ch)); } - // Write a Rust source file to use with rustdoc to generate intra-doc links. let tmp = TempDir::with_prefix("mdbook-spec-").unwrap(); - run_rustdoc(&tmp, &links, &chapter); + run_rustdoc(&tmp, &chapter_links); // Extract the links from the generated html. let generated = fs::read_to_string(tmp.path().join("doc/a/index.html")).expect("index.html generated"); - let urls: Vec<_> = STD_LINK_EXTRACT_RE + let mut urls: Vec<_> = STD_LINK_EXTRACT_RE .captures_iter(&generated) .map(|cap| cap.get(1).unwrap().as_str()) .collect(); - if urls.len() != links.len() { + let expected_len: usize = chapter_links.values().map(|l| l.len()).sum(); + if urls.len() != expected_len { eprintln!( - "error: expected rustdoc to generate {} links, but found {} in chapter {} ({:?})", - links.len(), + "error: expected rustdoc to generate {} links, but found {}", + expected_len, urls.len(), - chapter.name, - chapter.source_path.as_ref().unwrap() ); process::exit(1); } + // Unflatten the urls list so that it is split back by chapter. + let mut ch_urls: HashMap<&PathBuf, Vec<_>> = HashMap::new(); + for (ch_path, links) in &chapter_links { + let rest = urls.split_off(links.len()); + ch_urls.insert(ch_path, urls); + urls = rest; + } - // Replace any disambiguated links with just the disambiguation. - let mut output = STD_LINK_RE - .replace_all(&chapter.content, |caps: &Captures<'_>| { - if let Some(dest) = caps.get(2) { - // Replace destination parenthesis with a link definition (square brackets). - format!("{}[{}]", &caps[1], dest.as_str()) - } else { - caps[0].to_string() - } - }) - .to_string(); - - // Append the link definitions to the bottom of the chapter. - write!(output, "\n").unwrap(); - for ((link, dest), url) in links.iter().zip(urls) { - // Convert links to be relative so that links work offline and - // with the linkchecker. - let url = relative_url(url, chapter); - if let Some(dest) = dest { - write!(output, "[{dest}]: {url}\n").unwrap(); - } else { - write!(output, "{link}: {url}\n").unwrap(); + // Do this in two passes to deal with lifetimes. + let mut ch_contents = HashMap::new(); + for item in book.iter() { + let BookItem::Chapter(ch) = item else { + continue; + }; + if ch.is_draft_chapter() { + continue; } + let key = ch.source_path.as_ref().unwrap(); + // Create a list of replacements to make in the raw markdown to point to the new url. + let replacements = compute_replacements(&ch.content, &chapter_links[key], &ch_urls[key]); + + let mut new_contents = ch.content.to_string(); + for (md_link, url, range) in replacements { + // Convert links to be relative so that links work offline and + // with the linkchecker. + let url = relative_url(url, ch); + // Note that this may orphan reference link definitions. This should + // probably remove them, but pulldown_cmark doesn't give the span for + // the reference definition. + new_contents.replace_range(range, &format!("{md_link}({url})")); + } + ch_contents.insert(key.clone(), new_contents); } - output + // Replace the content with the new content. + book.for_each_mut(|item| { + let BookItem::Chapter(ch) = item else { + return; + }; + if ch.is_draft_chapter() { + return; + } + let key = ch.source_path.as_ref().unwrap(); + let content = ch_contents.remove(key).unwrap(); + ch.content = content; + }); } -/// Collects all markdown links, excluding those that already have link definitions. -/// -/// Returns a `Vec` of `(link, Option)` where markdown text like -/// ``[`std::fmt`]`` would return that as a link. The dest is optional, for -/// example ``[`Option`](std::option::Option)`` would have the part in -/// parentheses as the dest. -fn collect_markdown_links(chapter: &Chapter) -> Vec<(&str, Option<&str>)> { - let mut links: Vec<_> = STD_LINK_RE - .captures_iter(&chapter.content) - .map(|cap| { - if let Some(no_dest) = cap.get(3) { - (no_dest.as_str(), None) - } else { - ( - cap.get(1).unwrap().as_str(), - Some(cap.get(2).unwrap().as_str()), - ) - } - }) - .collect(); - if links.is_empty() { - return vec![]; - } - links.sort(); - links.dedup(); - // Remove any links that already have a link definition. We don't want - // to override what the author explicitly specified. - let existing_labels: HashSet<_> = LINK_DEF_RE - .captures_iter(&chapter.content) - .map(|cap| cap.get(1).unwrap().as_str()) - .collect(); - links.retain(|(link, dest)| { - let mut tmp = None; - let label: &str = dest.map_or(link, |d| { - tmp = Some(format!("[`{d}`]")); - tmp.as_deref().unwrap() +#[derive(Debug)] +struct Link<'a> { + link_type: LinkType, + /// Where the link is going to, for example `std::ffi::OsString`. + dest_url: CowStr<'a>, + /// The span in the original markdown where the link is located. + /// + /// Note that during translation, all links will be converted to inline + /// links. That means that for reference-style links, the link reference + /// definition will end up being ignored in the final markdown. For + /// example, a link like ``[`OsString`]`` with a definition + /// ``[`OsString`]: std::ffi::OsString`` will convert the link to + /// ``[`OsString`](https://doc.rust-lang.org/std/ffi/struct.OsString.html)`. + range: Range, +} + +/// Collects all markdown links that look like they might be standard library links. +fn collect_markdown_links<'a>(chapter: &'a Chapter) -> Vec> { + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + opts.insert(Options::ENABLE_HEADING_ATTRIBUTES); + opts.insert(Options::ENABLE_SMART_PUNCTUATION); + + let mut broken_links = Vec::new(); + let mut links = Vec::new(); + + // Broken links are collected so that you can write something like + // `[std::option::Option]` which in pulldown_cmark's eyes is a broken + // link. However, that is the normal syntax for rustdoc. + let broken_link = |broken_link: BrokenLink| { + broken_links.push(Link { + link_type: broken_link.link_type, + // Necessary due to lifetime issues. + dest_url: CowStr::Boxed(broken_link.reference.into_string().into()), + range: broken_link.span.clone(), }); - !existing_labels.contains(label) - }); + None + }; + let parser = Parser::new_with_broken_link_callback(&chapter.content, opts, Some(broken_link)) + .into_offset_iter(); + for (event, range) in parser { + match event { + Event::Start(Tag::Link { + link_type, + dest_url, + title, + id: _, + }) => { + // Only collect links that are for the standard library. + if matches!(link_type, LinkType::Autolink | LinkType::Email) { + continue; + } + if dest_url.starts_with("http") + || dest_url.contains(".md") + || dest_url.contains(".html") + || dest_url.starts_with('#') + { + continue; + } + if !title.is_empty() { + eprintln!( + "error: titles in links are not supported\n\ + Link {dest_url} has title `{title}` found in chapter {} ({:?})", + chapter.name, + chapter.source_path.as_ref().unwrap() + ); + process::exit(1); + } + links.push(Link { + link_type, + dest_url, + range: range.clone(), + }); + } + _ => {} + } + } + links.extend(broken_links); links } @@ -150,7 +204,7 @@ fn collect_markdown_links(chapter: &Chapter) -> Vec<(&str, Option<&str>)> { /// generate intra-doc links on them. /// /// The output will be in the given `tmp` directory. -fn run_rustdoc(tmp: &TempDir, links: &[(&str, Option<&str>)], chapter: &Chapter) { +fn run_rustdoc(tmp: &TempDir, chapter_links: &HashMap<&PathBuf, Vec>) { let src_path = tmp.path().join("a.rs"); // Allow redundant since there could some in-scope things that are // technically not necessary, but we don't care about (like @@ -159,13 +213,29 @@ fn run_rustdoc(tmp: &TempDir, links: &[(&str, Option<&str>)], chapter: &Chapter) "#![deny(rustdoc::broken_intra_doc_links)]\n\ #![allow(rustdoc::redundant_explicit_links)]\n" ); - for (link, dest) in links { - write!(src, "//! - {link}").unwrap(); - if let Some(dest) = dest { - write!(src, "({})", dest).unwrap(); + // This uses a list to make easy to pull the links out of the generated HTML. + for (_ch_path, links) in chapter_links { + for link in links { + match link.link_type { + LinkType::Inline + | LinkType::Reference + | LinkType::Collapsed + | LinkType::Shortcut => { + writeln!(src, "//! - LINK: [{}]", link.dest_url).unwrap(); + } + LinkType::ReferenceUnknown + | LinkType::CollapsedUnknown + | LinkType::ShortcutUnknown => { + // These should only happen due to broken link replacements. + panic!("unexpected link type unknown {link:?}"); + } + LinkType::Autolink | LinkType::Email => { + panic!("link type should have been filtered {link:?}"); + } + } } - src.push('\n'); } + // Put some common things into scope so that links to them work. writeln!( src, "extern crate alloc;\n\ @@ -182,12 +252,7 @@ fn run_rustdoc(tmp: &TempDir, links: &[(&str, Option<&str>)], chapter: &Chapter) .output() .expect("rustdoc installed"); if !output.status.success() { - eprintln!( - "error: failed to extract std links ({:?}) in chapter {} ({:?})\n", - output.status, - chapter.name, - chapter.source_path.as_ref().unwrap() - ); + eprintln!("error: failed to extract std links ({:?})\n", output.status,); io::stderr().write_all(&output.stderr).unwrap(); process::exit(1); } @@ -202,7 +267,7 @@ fn relative_url(url: &str, chapter: &Chapter) -> String { // Set SPEC_RELATIVE=0 to disable this, which can be useful for working locally. if std::env::var("SPEC_RELATIVE").as_deref() != Ok("0") { let Some(url_start) = DOC_URL.shortest_match(url) else { - eprintln!("expected rustdoc URL to start with {DOC_URL:?}, got {url}"); + eprintln!("error: expected rustdoc URL to start with {DOC_URL:?}, got {url}"); std::process::exit(1); }; let url_path = &url[url_start..]; @@ -213,3 +278,58 @@ fn relative_url(url: &str, chapter: &Chapter) -> String { url.to_string() } } + +/// Computes the replacements to make in the markdown content. +/// +/// Returns a `Vec` of `(md_link, url, range)` where: +/// +/// - `md_link` is the markdown link string to show to the user (like `[foo]`). +/// - `url` is the URL to the standard library. +/// - `range` is the range in the original markdown to replace with the new link. +fn compute_replacements<'a>( + contents: &'a str, + links: &[Link<'_>], + urls: &[&'a str], +) -> Vec<(&'a str, &'a str, Range)> { + let mut replacements = Vec::new(); + + for (url, link) in urls.into_iter().zip(links) { + let Some(cap) = ANCHOR_URL.captures(url) else { + eprintln!("error: could not find anchor in:\n{url}\nlink={link:#?}"); + process::exit(1); + }; + let url = cap.get(1).unwrap().as_str(); + let md_link = &contents[link.range.clone()]; + + let range = link.range.clone(); + let add_link = |re: &Regex| { + let Some(cap) = re.captures(md_link) else { + eprintln!( + "error: expected link `{md_link}` of type {:?} to match regex {re}", + link.link_type + ); + process::exit(1); + }; + let md_link = cap.get(1).unwrap().as_str(); + replacements.push((md_link, url, range)); + }; + + match link.link_type { + LinkType::Inline => { + add_link(&MD_LINK_INLINE); + } + LinkType::Reference | LinkType::Collapsed => { + add_link(&MD_LINK_REFERENCE); + } + LinkType::Shortcut => { + add_link(&MD_LINK_SHORTCUT); + } + _ => { + panic!("unexpected link type: {link:#?}"); + } + } + } + // Sort and reverse (so that it can replace bottom-up so ranges don't shift). + replacements.sort_by(|a, b| b.2.clone().partial_cmp(a.2.clone()).unwrap()); + replacements +} From cf34668a85d71602657760e911cfa8dcd8c6d513 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 17 Aug 2024 11:43:51 -0700 Subject: [PATCH 020/189] Switch mdbook-spec to build with release This should speed things up a little, particularly when working locally. --- book.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book.toml b/book.toml index 77b8b88..404b8cc 100644 --- a/book.toml +++ b/book.toml @@ -18,7 +18,7 @@ smart-punctuation = true edition = "2021" [preprocessor.spec] -command = "cargo run --manifest-path mdbook-spec/Cargo.toml" +command = "cargo run --release --manifest-path mdbook-spec/Cargo.toml" [build] extra-watch-dirs = ["mdbook-spec/src"] From 9cc7fab06bea7d7760139544db7640e8aa2cf34d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 17 Aug 2024 11:46:37 -0700 Subject: [PATCH 021/189] Switch to automatic standard library links This removes the explicit links to the standard library. In particular, this makes it nicer to view locally since you can set SPEC_RELATIVE=0 to make the links work. There are a bunch of changes to the actual URL because rustdoc resolves re-exports to link to the original definition instead of the re-export site. From what I can tell, everything should otherwise be the same. Not all links were able to be converted due to some limitations in rustdoc, such as: - Links to rexports from std_arch don't work due to https://github.com/rust-lang/rust/issues/96506. - Links to keywords aren't supported. - Links to trait impls where the trait is not in the prelude doesn't work (they must be in scope). --- src/attributes/codegen.md | 4 +--- src/attributes/derive.md | 2 -- src/attributes/diagnostics.md | 1 - src/attributes/testing.md | 6 +++--- src/behavior-considered-undefined.md | 10 ++++----- src/conditional-compilation.md | 3 --- src/crates-and-source-files.md | 8 +++---- src/destructors.md | 7 +------ src/expressions.md | 1 - src/expressions/array-expr.md | 4 ++-- src/expressions/await-expr.md | 16 +++++++------- src/expressions/block-expr.md | 2 -- src/expressions/call-expr.md | 7 ++----- src/expressions/literal-expr.md | 9 +------- src/expressions/method-call-expr.md | 2 +- src/expressions/operator-expr.md | 4 ++-- src/inline-assembly.md | 6 +++--- src/input-format.md | 3 --- src/interior-mutability.md | 5 ----- src/introduction.md | 2 +- src/items/enumerations.md | 3 +-- src/items/functions.md | 2 +- src/items/unions.md | 6 ++---- src/names/preludes.md | 15 +------------- src/procedural-macros.md | 13 ++++++------ src/runtime.md | 6 +++--- src/special-types-and-traits.md | 31 +++++++++------------------- src/tokens.md | 2 +- src/type-coercions.md | 4 ++-- src/type-layout.md | 14 ++++++------- src/types/array.md | 1 - src/types/boolean.md | 3 +-- src/types/closure.md | 3 --- src/types/function-item.md | 3 --- src/types/pointer.md | 2 -- src/types/union.md | 1 - src/unsafe-keyword.md | 2 +- 37 files changed, 69 insertions(+), 144 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 0ccc013..f30c296 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -427,9 +427,7 @@ trait object whose methods are attributed. [undefined behavior]: ../behavior-considered-undefined.md [unsafe function]: ../unsafe-keyword.md [rust-abi]: ../items/external-blocks.md#abi -[`core::intrinsics::caller_location`]: ../../core/intrinsics/fn.caller_location.html -[`core::panic::Location::caller`]: ../../core/panic/struct.Location.html#method.caller -[`Location`]: ../../core/panic/struct.Location.html +[`Location`]: core::panic::Location ## The `instruction_set` attribute diff --git a/src/attributes/derive.md b/src/attributes/derive.md index bb5631f..44ce8c7 100644 --- a/src/attributes/derive.md +++ b/src/attributes/derive.md @@ -37,8 +37,6 @@ has no direct effect, but it may be used by tools and diagnostic lints to detect these automatically generated implementations. [_MetaListPaths_]: ../attributes.md#meta-item-attribute-syntax -[`Clone`]: ../../std/clone/trait.Clone.html -[`PartialEq`]: ../../std/cmp/trait.PartialEq.html [`impl` item]: ../items/implementations.md [items]: ../items.md [derive macros]: ../procedural-macros.md#derive-macros diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 4f1af4d..34dab59 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -491,7 +491,6 @@ error[E0277]: My Message for `ImportantTrait` implemented for `String` = note: Note 2 ``` -[`std::fmt`]: ../../std/fmt/index.html [Clippy]: https://github.com/rust-lang/rust-clippy [_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax [_MetaListPaths_]: ../attributes.md#meta-item-attribute-syntax diff --git a/src/attributes/testing.md b/src/attributes/testing.md index 2c3b292..a2db083 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -82,8 +82,8 @@ fn mytest() { [_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: ../attributes.md#meta-item-attribute-syntax -[`Termination`]: ../../std/process/trait.Termination.html -[`report`]: ../../std/process/trait.Termination.html#tymethod.report +[`Termination`]: std::process::Termination +[`report`]: std::process::Termination::report [`test` conditional compilation option]: ../conditional-compilation.md#test [attributes]: ../attributes.md -[`ExitCode`]: ../../std/process/struct.ExitCode.html +[`ExitCode`]: std::process::ExitCode diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 69c44bc..14d8ede 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -30,7 +30,7 @@ Please read the [Rustonomicon] before writing unsafe code. * Accessing (loading from or storing to) a place that is [dangling] or [based on a misaligned pointer]. * Performing a place projection that violates the requirements of [in-bounds - pointer arithmetic][offset]. A place projection is a [field + pointer arithmetic](pointer#method.offset). A place projection is a [field expression][project-field], a [tuple index expression][project-tuple], or an [array/slice index expression][project-slice]. * Breaking the [pointer aliasing rules]. `Box`, `&mut T` and `&T` follow @@ -176,16 +176,14 @@ reading uninitialized memory is permitted are inside `union`s and in "padding" [pointer aliasing rules]: http://llvm.org/docs/LangRef.html#pointer-aliasing-rules [undef]: http://llvm.org/docs/LangRef.html#undefined-values [`target_feature`]: attributes/codegen.md#the-target_feature-attribute -[`UnsafeCell`]: ../std/cell/struct.UnsafeCell.html +[`UnsafeCell`]: std::cell::UnsafeCell [Rustonomicon]: ../nomicon/index.html -[`NonNull`]: ../core/ptr/struct.NonNull.html -[`NonZero`]: ../core/num/struct.NonZero.html -[`Box`]: ../alloc/boxed/struct.Box.html +[`NonNull`]: core::ptr::NonNull +[`NonZero`]: core::num::NonZero [place expression context]: expressions.md#place-expressions-and-value-expressions [rules]: inline-assembly.md#rules-for-inline-assembly [points to]: #pointed-to-bytes [pointed to]: #pointed-to-bytes -[offset]: ../std/primitive.pointer.html#method.offset [project-field]: expressions/field-expr.md [project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions [project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index f98b323..e445475 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -201,8 +201,6 @@ atomic loads, stores, and compare-and-swap operations. When this cfg is present, all of the stable [`core::sync::atomic`] APIs are available for the relevant atomic width. -[`core::sync::atomic`]: ../core/sync/atomic/index.html - Possible values: * `"8"` @@ -374,7 +372,6 @@ println!("I'm running on a {} machine!", machine_kind); [`cfg`]: #the-cfg-attribute [`cfg` macro]: #the-cfg-macro [`cfg_attr`]: #the-cfg_attr-attribute -[`debug_assert!`]: ../std/macro.debug_assert.html [`target_feature` attribute]: attributes/codegen.md#the-target_feature-attribute [attribute]: attributes.md [attributes]: attributes.md diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index b0e607b..426ee26 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -129,14 +129,14 @@ or `_` (U+005F) characters. ECMA-335 CLI model, a *library* in the SML/NJ Compilation Manager, a *unit* in the Owens and Flatt module system, or a *configuration* in Mesa. -[Unicode alphanumeric]: ../std/primitive.char.html#method.is_alphanumeric +[Unicode alphanumeric]: char::is_alphanumeric [`!`]: types/never.md [_InnerAttribute_]: attributes.md [_Item_]: items.md [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax -[`ExitCode`]: ../std/process/struct.ExitCode.html -[`Infallible`]: ../std/convert/enum.Infallible.html -[`Termination`]: ../std/process/trait.Termination.html +[`ExitCode`]: std::process::ExitCode +[`Infallible`]: std::convert::Infallible +[`Termination`]: std::process::Termination [attribute]: attributes.md [attributes]: attributes.md [function]: items/functions.md diff --git a/src/destructors.md b/src/destructors.md index 9c42642..680a962 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -8,7 +8,7 @@ dropped. The destructor of a type `T` consists of: -1. If `T: Drop`, calling [`::drop`] +1. If `T: Drop`, calling [`::drop`](std::ops::Drop::drop) 2. Recursively running the destructor of all of its fields. * The fields of a [struct] are dropped in declaration order. * The fields of the active [enum variant] are dropped in declaration order. @@ -400,8 +400,3 @@ variable or field from being dropped automatically. [`match`]: expressions/match-expr.md [`while let`]: expressions/loop-expr.md#predicate-pattern-loops [`while`]: expressions/loop-expr.md#predicate-loops - -[`::drop`]: ../std/ops/trait.Drop.html#tymethod.drop -[`std::ptr::drop_in_place`]: ../std/ptr/fn.drop_in_place.html -[`std::mem::forget`]: ../std/mem/fn.forget.html -[`std::mem::ManuallyDrop`]: ../std/mem/struct.ManuallyDrop.html diff --git a/src/expressions.md b/src/expressions.md index 9e10dce..208ac95 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -284,7 +284,6 @@ They are never allowed before: [destructors]: destructors.md [drop scope]: destructors.md#drop-scopes -[`Box`]: ../std/boxed/struct.Box.html [`Copy`]: special-types-and-traits.md#copy [`Drop`]: special-types-and-traits.md#drop [`Sized`]: special-types-and-traits.md#sized diff --git a/src/expressions/array-expr.md b/src/expressions/array-expr.md index fd7e2d3..52d3194 100644 --- a/src/expressions/array-expr.md +++ b/src/expressions/array-expr.md @@ -76,8 +76,8 @@ arr[10]; // warning: index out of bounds The array index expression can be implemented for types other than arrays and slices by implementing the [Index] and [IndexMut] traits. [`Copy`]: ../special-types-and-traits.md#copy -[IndexMut]: ../../std/ops/trait.IndexMut.html -[Index]: ../../std/ops/trait.Index.html +[IndexMut]: std::ops::IndexMut +[Index]: std::ops::Index [_Expression_]: ../expressions.md [array]: ../types/array.md [constant expression]: ../const_eval.md#constant-expressions diff --git a/src/expressions/await-expr.md b/src/expressions/await-expr.md index feea1a3..ae12989 100644 --- a/src/expressions/await-expr.md +++ b/src/expressions/await-expr.md @@ -49,12 +49,12 @@ The variable `current_context` refers to the context taken from the async enviro [_Expression_]: ../expressions.md [`async fn`]: ../items/functions.md#async-functions [`async` block]: block-expr.md#async-blocks -[`context`]: ../../std/task/struct.Context.html -[`future::poll`]: ../../std/future/trait.Future.html#tymethod.poll -[`pin::new_unchecked`]: ../../std/pin/struct.Pin.html#method.new_unchecked -[`poll::Pending`]: ../../std/task/enum.Poll.html#variant.Pending -[`poll::Ready`]: ../../std/task/enum.Poll.html#variant.Ready +[`Context`]: std::task::Context +[`future::poll`]: std::future::Future::poll +[`pin::new_unchecked`]: std::pin::Pin::new_unchecked +[`poll::Pending`]: std::task::Poll::Pending +[`poll::Ready`]: std::task::Poll::Ready [async context]: ../expressions/block-expr.md#async-context -[future]: ../../std/future/trait.Future.html -[`IntoFuture`]: ../../std/future/trait.IntoFuture.html -[`IntoFuture::into_future`]: ../../std/future/trait.IntoFuture.html#tymethod.into_future +[future]: std::future::Future +[`IntoFuture`]: std::future::IntoFuture +[`IntoFuture::into_future`]: std::future::IntoFuture::into_future diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md index 08baec3..55936e3 100644 --- a/src/expressions/block-expr.md +++ b/src/expressions/block-expr.md @@ -231,8 +231,6 @@ fn is_unix_platform() -> bool { [`cfg`]: ../conditional-compilation.md [`for`]: loop-expr.md#iterator-loops [`loop`]: loop-expr.md#infinite-loops -[`std::ops::Fn`]: ../../std/ops/trait.Fn.html -[`std::future::Future`]: ../../std/future/trait.Future.html [`unsafe` blocks]: ../unsafe-keyword.md#unsafe-blocks-unsafe- [`while let`]: loop-expr.md#predicate-pattern-loops [`while`]: loop-expr.md#predicate-loops diff --git a/src/expressions/call-expr.md b/src/expressions/call-expr.md index 7a01e92..64df58c 100644 --- a/src/expressions/call-expr.md +++ b/src/expressions/call-expr.md @@ -87,11 +87,8 @@ Refer to [RFC 132] for further details and motivations. [RFC 132]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md [_Expression_]: ../expressions.md -[`default()`]: ../../std/default/trait.Default.html#tymethod.default -[`size_of()`]: ../../std/mem/fn.size_of.html -[`std::ops::FnMut`]: ../../std/ops/trait.FnMut.html -[`std::ops::FnOnce`]: ../../std/ops/trait.FnOnce.html -[`std::ops::Fn`]: ../../std/ops/trait.Fn.html +[`default()`]: std::default::Default::default +[`size_of()`]: std::mem::size_of [automatically dereferenced]: field-expr.md#automatic-dereferencing [fully-qualified syntax]: ../paths.md#qualified-paths [non-function types]: ../types/function-item.md diff --git a/src/expressions/literal-expr.md b/src/expressions/literal-expr.md index 2d8d5f9..2216907 100644 --- a/src/expressions/literal-expr.md +++ b/src/expressions/literal-expr.md @@ -419,7 +419,7 @@ The expression's type is the primitive [boolean type], and its value is: [String continuation escapes]: #string-continuation-escapes [boolean type]: ../types/boolean.md [constant expression]: ../const_eval.md#constant-expressions -[CStr]: ../../core/ffi/struct.CStr.html +[CStr]: core::ffi::CStr [floating-point types]: ../types/numeric.md#floating-point-types [lint check]: ../attributes/diagnostics.md#lint-check-attributes [literal tokens]: ../tokens.md#literals @@ -432,14 +432,7 @@ The expression's type is the primitive [boolean type], and its value is: [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value [Unicode scalar values]: http://www.unicode.org/glossary/#unicode_scalar_value [`f32::from_str`]: ../../core/primitive.f32.md#method.from_str -[`f32::INFINITY`]: ../../core/primitive.f32.md#associatedconstant.INFINITY -[`f32::NAN`]: ../../core/primitive.f32.md#associatedconstant.NAN [`f64::from_str`]: ../../core/primitive.f64.md#method.from_str -[`f64::INFINITY`]: ../../core/primitive.f64.md#associatedconstant.INFINITY -[`f64::NAN`]: ../../core/primitive.f64.md#associatedconstant.NAN -[`u8::from_str_radix`]: ../../core/primitive.u8.md#method.from_str_radix -[`u32::from_str_radix`]: ../../core/primitive.u32.md#method.from_str_radix -[`u128::from_str_radix`]: ../../core/primitive.u128.md#method.from_str_radix [CHAR_LITERAL]: ../tokens.md#character-literals [STRING_LITERAL]: ../tokens.md#string-literals [RAW_STRING_LITERAL]: ../tokens.md#raw-string-literals diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index 8a2f68c..7f21c49 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -93,4 +93,4 @@ Just don't define inherent methods on trait objects with the same name as a trai [dereference]: operator-expr.md#the-dereference-operator [methods]: ../items/associated-items.md#methods [unsized coercion]: ../type-coercions.md#unsized-coercions -[`IntoIterator`]: ../../std/iter/trait.IntoIterator.html +[`IntoIterator`]: std::iter::IntoIterator diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index cd9e5e1..0601a86 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -674,8 +674,8 @@ See [this test] for an example of using this dependency. [Function pointer]: ../types/function-pointer.md [Function item]: ../types/function-item.md [undefined behavior]: ../behavior-considered-undefined.md -[addr_of]: ../../std/ptr/macro.addr_of.html -[addr_of_mut]: ../../std/ptr/macro.addr_of_mut.html +[addr_of]: std::ptr::addr_of +[addr_of_mut]: std::ptr::addr_of_mut [_BorrowExpression_]: #borrow-operators [_DereferenceExpression_]: #the-dereference-operator diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 960fff1..9dd02e2 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -6,8 +6,8 @@ r[asm.intro] Support for inline assembly is provided via the [`asm!`] and [`global_asm!`] macros. It can be used to embed handwritten assembly in the assembly output generated by the compiler. -[`asm!`]: ../core/arch/macro.asm.html -[`global_asm!`]: ../core/arch/macro.global_asm.html +[`asm!`]: core::arch::asm +[`global_asm!`]: core::arch::global_asm r[asm.stable-targets] Support for inline assembly is stable on the following architectures: @@ -119,7 +119,7 @@ These targets impose an additional restriction on the assembly code: any assembl Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior. Further constraints on the directives used by inline assembly are indicated by [Directives Support](#directives-support). -[format-syntax]: ../std/fmt/index.html#syntax +[format-syntax]: std::fmt#syntax [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795 ## Operand type diff --git a/src/input-format.md b/src/input-format.md index 8d921bf..aad45ac 100644 --- a/src/input-format.md +++ b/src/input-format.md @@ -44,9 +44,6 @@ This prevents an [inner attribute] at the start of a source file being removed. The resulting sequence of characters is then converted into tokens as described in the remainder of this chapter. -[`include!`]: ../std/macro.include.md -[`include_bytes!`]: ../std/macro.include_bytes.md -[`include_str!`]: ../std/macro.include_str.md [inner attribute]: attributes.md [BYTE ORDER MARK]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 [comments]: comments.md diff --git a/src/interior-mutability.md b/src/interior-mutability.md index 9146007..dc79aac 100644 --- a/src/interior-mutability.md +++ b/src/interior-mutability.md @@ -22,8 +22,3 @@ across threads. [shared reference]: types/pointer.md#shared-references- [ub]: behavior-considered-undefined.md -[`std::cell::UnsafeCell`]: ../std/cell/struct.UnsafeCell.html -[`std::cell::RefCell`]: ../std/cell/struct.RefCell.html -[`std::sync::atomic`]: ../std/sync/atomic/index.html - - diff --git a/src/introduction.md b/src/introduction.md index 9038efd..7f01096 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -131,7 +131,7 @@ We also want the reference to be as normative as possible, so if you see anythin [book]: ../book/index.html [github issues]: https://github.com/rust-lang/reference/issues -[standard library]: ../std/index.html +[standard library]: std [the Rust Reference repository]: https://github.com/rust-lang/reference/ [Unstable Book]: https://doc.rust-lang.org/nightly/unstable-book/ [_Expression_]: expressions.md diff --git a/src/items/enumerations.md b/src/items/enumerations.md index 5f00846..63a3e76 100644 --- a/src/items/enumerations.md +++ b/src/items/enumerations.md @@ -197,7 +197,7 @@ enum OverflowingDiscriminantError2 { #### Via `mem::discriminant` -[`mem::discriminant`] returns an opaque reference to the discriminant of +[`std::mem::discriminant`] returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant. @@ -331,7 +331,6 @@ enum E { [_Visibility_]: ../visibility-and-privacy.md [_WhereClause_]: generics.md#where-clauses [`C` representation]: ../type-layout.md#the-c-representation -[`mem::discriminant`]: ../../std/mem/fn.discriminant.html [call expression]: ../expressions/call-expr.md [constant expression]: ../const_eval.md#constant-expressions [default representation]: ../type-layout.md#the-default-representation diff --git a/src/items/functions.md b/src/items/functions.md index 54988df..2a12708 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -418,7 +418,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [`export_name`]: ../abi.md#the-export_name-attribute [`link_section`]: ../abi.md#the-link_section-attribute [`no_mangle`]: ../abi.md#the-no_mangle-attribute -[built-in attributes]: ../attributes.html#built-in-attributes-index +[built-in attributes]: ../attributes.md#built-in-attributes-index [trait item]: traits.md [method]: associated-items.md#methods [associated function]: associated-items.md#associated-functions-and-methods diff --git a/src/items/unions.md b/src/items/unions.md index ed3ba5a..d6a03ed 100644 --- a/src/items/unions.md +++ b/src/items/unions.md @@ -175,10 +175,8 @@ checking, etc etc etc). [_GenericParams_]: generics.md [_WhereClause_]: generics.md#where-clauses [_StructFields_]: structs.md -[`transmute`]: ../../std/mem/fn.transmute.html -[`Copy`]: ../../std/marker/trait.Copy.html +[`transmute`]: std::mem::transmute [boolean type]: ../types/boolean.md -[ManuallyDrop]: ../../std/mem/struct.ManuallyDrop.html [the C representation]: ../type-layout.md#reprc-unions [type namespace]: ../names/namespaces.md -[undefined behavior]: ../behavior-considered-undefined.html +[undefined behavior]: ../behavior-considered-undefined.md diff --git a/src/names/preludes.md b/src/names/preludes.md index f557699..745b290 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -52,7 +52,7 @@ added as long as the [`no_std` attribute] is not specified in the crate root. > the extern prelude, so it is considered unidiomatic to use `extern crate`. > **Note**: Additional crates that ship with `rustc`, such as [`alloc`], and -> [`test`], are not automatically included with the `--extern` flag when using +> [`test`](mod@test), are not automatically included with the `--extern` flag when using > Cargo. They must be brought into scope with an `extern crate` declaration, > even in the 2018 edition. > @@ -137,24 +137,11 @@ This attribute does not affect the [language prelude]. > from the standard library are still included in the `macro_use` prelude. > Starting in the 2018 edition, it will remove the `macro_use` prelude. -[`alloc`]: ../../alloc/index.html -[`Box`]: ../../std/boxed/struct.Box.html -[`core::prelude::v1`]: ../../core/prelude/v1/index.html -[`core::prelude::rust_2015`]: ../../core/prelude/rust_2015/index.html -[`core::prelude::rust_2018`]: ../../core/prelude/rust_2018/index.html -[`core::prelude::rust_2021`]: ../../core/prelude/rust_2021/index.html -[`core`]: ../../core/index.html [`extern crate`]: ../items/extern-crates.md [`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 -[`std::prelude::v1`]: ../../std/prelude/v1/index.html -[`std::prelude::rust_2015`]: ../../std/prelude/rust_2015/index.html -[`std::prelude::rust_2018`]: ../../std/prelude/rust_2018/index.html -[`std::prelude::rust_2021`]: ../../std/prelude/rust_2021/index.html -[`std`]: ../../std/index.html -[`test`]: ../../test/index.html [attribute]: ../attributes.md [Boolean type]: ../types/boolean.md [Built-in attributes]: ../attributes.md#built-in-attributes-index diff --git a/src/procedural-macros.md b/src/procedural-macros.md index c5af448..a97755f 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -338,16 +338,15 @@ their equivalent `#[doc = r"str"]` attributes when passed to macros. [Cargo's build scripts]: ../cargo/reference/build-scripts.html [Derive macros]: #derive-macros [Function-like macros]: #function-like-procedural-macros -[`Delimiter::None`]: ../proc_macro/enum.Delimiter.html#variant.None -[`Group`]: ../proc_macro/struct.Group.html -[`TokenStream`]: ../proc_macro/struct.TokenStream.html -[`TokenStream`s]: ../proc_macro/struct.TokenStream.html -[`TokenTree`s]: ../proc_macro/enum.TokenTree.html -[`compile_error`]: ../std/macro.compile_error.html +[`Delimiter::None`]: proc_macro::Delimiter::None +[`Group`]: proc_macro::Group +[`TokenStream`]: proc_macro::TokenStream +[`TokenStream`s]: proc_macro::TokenStream +[`TokenTree`s]: proc_macro::TokenTree [`derive` attribute]: attributes/derive.md [`extern` blocks]: items/external-blocks.md [`macro_rules`]: macros-by-example.md -[`proc_macro` crate]: ../proc_macro/index.html +[`proc_macro` crate]: proc_macro [attribute]: attributes.md [attributes]: attributes.md [block]: expressions/block-expr.md diff --git a/src/runtime.md b/src/runtime.md index a281d50..a673834 100644 --- a/src/runtime.md +++ b/src/runtime.md @@ -75,11 +75,11 @@ display a console window on startup. It will run detached from any existing cons ``` [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax -[`GlobalAlloc`]: ../alloc/alloc/trait.GlobalAlloc.html -[`PanicInfo`]: ../core/panic/struct.PanicInfo.html +[`GlobalAlloc`]: alloc::alloc::GlobalAlloc +[`PanicInfo`]: core::panic::PanicInfo [abort]: ../book/ch09-01-unrecoverable-errors-with-panic.html [attribute]: attributes.md [crate types]: linkage.md -[set_hook]: ../std/panic/fn.set_hook.html +[set_hook]: std::panic::set_hook [static item]: items/static-items.md [subsystem]: https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx diff --git a/src/special-types-and-traits.md b/src/special-types-and-traits.md index 21cab3d..f7e9832 100644 --- a/src/special-types-and-traits.md +++ b/src/special-types-and-traits.md @@ -140,26 +140,15 @@ The [`Sized`] trait indicates that the size of this type is known at compile-tim `Sized` is always implemented automatically by the compiler, not by [implementation items]. These implicit `Sized` bounds may be relaxed by using the special `?Sized` bound. -[`Arc`]: ../std/sync/struct.Arc.html -[`Box`]: ../std/boxed/struct.Box.html -[`Clone`]: ../std/clone/trait.Clone.html -[`Copy`]: ../std/marker/trait.Copy.html -[`Deref`]: ../std/ops/trait.Deref.html -[`DerefMut`]: ../std/ops/trait.DerefMut.html -[`Drop`]: ../std/ops/trait.Drop.html -[`Pin

    `]: ../std/pin/struct.Pin.html -[`Rc`]: ../std/rc/struct.Rc.html -[`RefUnwindSafe`]: ../std/panic/trait.RefUnwindSafe.html -[`Send`]: ../std/marker/trait.Send.html -[`Sized`]: ../std/marker/trait.Sized.html -[`std::cell::UnsafeCell`]: ../std/cell/struct.UnsafeCell.html -[`std::cmp`]: ../std/cmp/index.html -[`std::marker::PhantomData`]: ../std/marker/struct.PhantomData.html -[`std::ops`]: ../std/ops/index.html -[`Termination`]: ../std/process/trait.Termination.html -[`UnwindSafe`]: ../std/panic/trait.UnwindSafe.html -[`Sync`]: ../std/marker/trait.Sync.html -[`Unpin`]: ../std/marker/trait.Unpin.html +[`Arc`]: std::sync::Arc +[`Deref`]: std::ops::Deref +[`DerefMut`]: std::ops::DerefMut +[`Pin

    `]: std::pin::Pin +[`Rc`]: std::rc::Rc +[`RefUnwindSafe`]: std::panic::RefUnwindSafe +[`Termination`]: std::process::Termination +[`UnwindSafe`]: std::panic::UnwindSafe +[`Unpin`]: std::marker::Unpin [Arrays]: types/array.md [associated types]: items/associated-items.md#associated-types @@ -181,7 +170,7 @@ These implicit `Sized` bounds may be relaxed by using the special `?Sized` bound [orphan rules]: items/implementations.md#trait-implementation-coherence [`static` items]: items/static-items.md [test functions]: attributes/testing.md#the-test-attribute -[the standard library]: ../std/index.html +[the standard library]: std [trait object]: types/trait-object.md [Tuples]: types/tuple.md [Type parameters]: types/parameters.md diff --git a/src/tokens.md b/src/tokens.md index 1c50ed1..aeafe4b 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -336,7 +336,7 @@ followed by the character `U+0022`. If the character `U+0022` is present within the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character. Alternatively, a C string literal can be a _raw C string literal_, defined below. -[CStr]: ../core/ffi/struct.CStr.html +[CStr]: core::ffi::CStr C strings are implicitly terminated by byte `0x00`, so the C string literal `c""` is equivalent to manually constructing a `&CStr` from the byte string diff --git a/src/type-coercions.md b/src/type-coercions.md index f1016b1..7d254f4 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -271,6 +271,6 @@ precisely. [subtype]: subtyping.md [object safe]: items/traits.md#object-safety [type cast operator]: expressions/operator-expr.md#type-cast-expressions -[`Unsize`]: ../std/marker/trait.Unsize.html -[`CoerceUnsized`]: ../std/ops/trait.CoerceUnsized.html +[`Unsize`]: std::marker::Unsize +[`CoerceUnsized`]: std::ops::CoerceUnsized [method-call expressions]: expressions/method-call-expr.md diff --git a/src/type-layout.md b/src/type-layout.md index c53e9d0..8b1a689 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -600,12 +600,12 @@ primitive field will have the ABI of the primitive field. Because this representation delegates type layout to another type, it cannot be used with any other representation. -[`align_of_val`]: ../std/mem/fn.align_of_val.html -[`size_of_val`]: ../std/mem/fn.size_of_val.html -[`align_of`]: ../std/mem/fn.align_of.html -[`size_of`]: ../std/mem/fn.size_of.html -[`Sized`]: ../std/marker/trait.Sized.html -[`Copy`]: ../std/marker/trait.Copy.html +[`align_of_val`]: std::mem::align_of_val +[`size_of_val`]: std::mem::size_of_val +[`align_of`]: std::mem::align_of +[`size_of`]: std::mem::size_of +[`Sized`]: std::marker::Sized +[`Copy`]: std::marker::Copy [dynamically sized types]: dynamically-sized-types.md [field-less enums]: items/enumerations.md#field-less-enum [enumerations]: items/enumerations.md @@ -618,4 +618,4 @@ used with any other representation. [primitive representations]: #primitive-representations [structs]: items/structs.md [`transparent`]: #the-transparent-representation -[`Layout`]: ../std/alloc/struct.Layout.html +[`Layout`]: std::alloc::Layout diff --git a/src/types/array.md b/src/types/array.md index 88ea863..167954b 100644 --- a/src/types/array.md +++ b/src/types/array.md @@ -26,6 +26,5 @@ always bounds-checked in safe methods and operators. [_Expression_]: ../expressions.md [_Type_]: ../types.md#type-expressions -[`Vec`]: ../../std/vec/struct.Vec.html [`usize`]: numeric.md#machine-dependent-integer-types [constant expression]: ../const_eval.md#constant-expressions diff --git a/src/types/boolean.md b/src/types/boolean.md index 7ea99d1..a0c0710 100644 --- a/src/types/boolean.md +++ b/src/types/boolean.md @@ -30,7 +30,7 @@ Like all primitives, the boolean type [implements][p-impl] the [traits][p-traits] [`Clone`][p-clone], [`Copy`][p-copy], [`Sized`][p-sized], [`Send`][p-send], and [`Sync`][p-sync]. -> **Note**: See the [standard library docs][std] for library operations. +> **Note**: See the [standard library docs](bool) for library operations. ## Operations on boolean values @@ -119,6 +119,5 @@ are invalid `bool`s, the inverse is not always sound). [p-sync]: ../special-types-and-traits.md#sync [p-traits]: ../items/traits.md [size and alignment]: ../type-layout.md#size-and-alignment -[std]: ../../std/primitive.bool.html [undefined behavior]: ../behavior-considered-undefined.md [while expressions]: ../expressions/loop-expr.md#predicate-loops diff --git a/src/types/closure.md b/src/types/closure.md index eecdb03..f935378 100644 --- a/src/types/closure.md +++ b/src/types/closure.md @@ -170,9 +170,6 @@ Because captures are often by reference, the following general rules arise: [`Clone`]: ../special-types-and-traits.md#clone [`Copy`]: ../special-types-and-traits.md#copy -[`FnMut`]: ../../std/ops/trait.FnMut.html -[`FnOnce`]: ../../std/ops/trait.FnOnce.html -[`Fn`]: ../../std/ops/trait.Fn.html [`Send`]: ../special-types-and-traits.md#send [`Sized`]: ../special-types-and-traits.md#sized [`Sync`]: ../special-types-and-traits.md#sync diff --git a/src/types/function-item.md b/src/types/function-item.md index c8088e4..3221f3e 100644 --- a/src/types/function-item.md +++ b/src/types/function-item.md @@ -48,9 +48,6 @@ All function items implement [`Fn`], [`FnMut`], [`FnOnce`], [`Copy`], [`Clone`]: ../special-types-and-traits.md#clone [`Copy`]: ../special-types-and-traits.md#copy -[`FnMut`]: ../../std/ops/trait.FnMut.html -[`FnOnce`]: ../../std/ops/trait.FnOnce.html -[`Fn`]: ../../std/ops/trait.Fn.html [`Send`]: ../special-types-and-traits.md#send [`Sync`]: ../special-types-and-traits.md#sync [coercion]: ../type-coercions.md diff --git a/src/types/pointer.md b/src/types/pointer.md index cbbf356..a1ec509 100644 --- a/src/types/pointer.md +++ b/src/types/pointer.md @@ -60,8 +60,6 @@ For thin raw pointers (i.e., for `P = *const T` or `P = *mut T` for `T: Sized`), the inverse direction (transmuting from an integer or array of integers to `P`) is always valid. However, the pointer produced via such a transmutation may not be dereferenced (not even if `T` has size zero). -[`core::ptr::addr_of!`]: ../../core/ptr/macro.addr_of.html -[`core::ptr::addr_of_mut!`]: ../../core/ptr/macro.addr_of_mut.html [Interior mutability]: ../interior-mutability.md [_Lifetime_]: ../trait-bounds.md [_TypeNoBounds_]: ../types.md#type-expressions diff --git a/src/types/union.md b/src/types/union.md index 326e720..7a2f037 100644 --- a/src/types/union.md +++ b/src/types/union.md @@ -15,5 +15,4 @@ The memory layout of a `union` is undefined by default (in particular, fields do fix a layout. [`Copy`]: ../special-types-and-traits.md#copy -[`ManuallyDrop`]: ../../std/mem/struct.ManuallyDrop.html [item]: ../items/unions.md diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index df68a74..175a5e8 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -54,7 +54,7 @@ By writing `unsafe impl`, the programmer states that they have taken care of sat Unsafe trait implementations are the logical dual to unsafe traits: where unsafe traits define a proof obligation that implementations must uphold, unsafe implementations state that all relevant proof obligations have been discharged. [keyword]: ../std/keyword.unsafe.html -[`get_unchecked`]: ../std/primitive.slice.html#method.get_unchecked +[`get_unchecked`]: slice::get_unchecked [`unsafe_op_in_unsafe_fn`]: ../rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn ## Unsafe external blocks (`unsafe extern`) From d8afb6bdb16f2d7c415667d284990363e85d9ea0 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 17 Aug 2024 11:56:26 -0700 Subject: [PATCH 022/189] Note some limitations of automatic std links --- docs/authoring.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/authoring.md b/docs/authoring.md index 256cb30..a01c8a5 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -109,6 +109,15 @@ Explicit namespace disambiguation is also supported: [`std::vec`](mod@std::vec) ``` +Beware there are some limitations, for example: + +- Links to rexports from `std_arch` don't work due to . +- Links to keywords aren't supported. +- Links to trait impls where the trait is not in the prelude doesn't work. Traits must be in scope, and there currently isn't a way to add those. +- If there are multiple generic implementations, it will link to one randomly (see ). + +When running into a rustdoc limitation, consider manually linking to the correct page using a relative link. For example, `../std/arch/macro.is_x86_feature_detected.html`. + [intra]: https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html ### Admonitions From caf5eddef26ed346284de1868f83e24f45f77f5b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 17 Aug 2024 11:56:54 -0700 Subject: [PATCH 023/189] Document the SPEC_RELATIVE option --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 009a3d8..a296a3b 100644 --- a/README.md +++ b/README.md @@ -61,13 +61,15 @@ To build the Reference locally (in `build/`) and open it in a web browser, run: ```sh -mdbook build --open +SPEC_RELATIVE=0 mdbook build --open ``` This will open a browser with a websocket live-link to automatically reload whenever the source is updated. -You can also open any current build of the reference by running: +The `SPEC_RELATIVE=0` environment variable makes links to the standard library go to instead of being relative, which is useful when viewing locally since you normally don't have a copy of the standard library. + +You can also use mdbook's live webserver option, which will automatically rebuild the book and reload your web browser whenever a source file is modified: ```sh -mdbook serve --open +SPEC_RELATIVE=0 mdbook serve --open ``` From 7de0d01b50f22307030cb3a75cd916b4b2ddeb1f Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 20 Jul 2024 20:19:25 -0500 Subject: [PATCH 024/189] Add some basic docs for unsafe attrs --- src/abi.md | 10 ++++++++++ src/attributes.md | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/abi.md b/src/abi.md index 374dd6d..9317272 100644 --- a/src/abi.md +++ b/src/abi.md @@ -66,12 +66,19 @@ item's name. Additionally, the item will be publicly exported from the produced library or object file, similar to the [`used` attribute](#the-used-attribute). +This attribute is unsafe as an unmangled symbol may collide with another +symbol with the same name (or a well-known symbol), leading to undefined behavior. + ## The `link_section` attribute The *`link_section` attribute* specifies the section of the object file that a [function] or [static]'s content will be placed into. It uses the [_MetaNameValueStr_] syntax to specify the section name. +This attribute is unsafe as using `link_section` allows users to place data +and code into sections of memory not expecting them, such as mutable data +into read-only areas. + ```rust,no_run #[no_mangle] @@ -85,6 +92,9 @@ The *`export_name` attribute* specifies the name of the symbol that will be exported on a [function] or [static]. It uses the [_MetaNameValueStr_] syntax to specify the symbol name. +This attribute is unsafe as a symbol with a custom name may collide with another +symbol with the same name (or a well-known symbol), leading to undefined behavior. + ```rust #[export_name = "exported_symbol_name"] pub fn name_in_rust() { } diff --git a/src/attributes.md b/src/attributes.md index a56e276..a2ed37f 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -4,9 +4,13 @@ > **Syntax**\ > _InnerAttribute_ :\ >    `#` `!` `[` _Attr_ `]` +>    `#` `!` `[` `unsafe` `(` _Attr_ `)` `]` > > _OuterAttribute_ :\ >    `#` `[` _Attr_ `]` +>    `#` `[` `unsafe` `(` _Attr_ `)` `]` +>    `#` `!` `[` _Attr_ `]` +>    `#` `!` `[` `unsafe` `(` _Attr_ `)` `]` > > _Attr_ :\ >    [_SimplePath_] _AttrInput_? @@ -29,6 +33,16 @@ Attributes other than macro attributes also allow the input to be an equals sign (`=`) followed by an expression. See the [meta item syntax](#meta-item-attribute-syntax) below for more details. +An attribute may be considered unsafe. Unsafe attributes must *satisfy* extra +safety conditions that cannot be checked by the compiler, and are specified +as the attribute wrapped in `unsafe(...)`, for instance, `#[unsafe(no_mangle)]`. + +The following attributes are unsafe: + +* [`export_name`] +* [`link_section`] +* [`no_mangle`] + Attributes can be classified into the following kinds: * [Built-in attributes] From 501e757a772f0debf7770722ae03f57a233f94c7 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 22 Jul 2024 07:31:13 +0000 Subject: [PATCH 025/189] Wordsmith text for unsafe attributes In this commit, we improve some verbiage. --- src/abi.md | 12 ++++++------ src/attributes.md | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/abi.md b/src/abi.md index 9317272..47116f5 100644 --- a/src/abi.md +++ b/src/abi.md @@ -66,8 +66,8 @@ item's name. Additionally, the item will be publicly exported from the produced library or object file, similar to the [`used` attribute](#the-used-attribute). -This attribute is unsafe as an unmangled symbol may collide with another -symbol with the same name (or a well-known symbol), leading to undefined behavior. +This attribute is unsafe as an unmangled symbol may collide with another symbol +with the same name (or with a well-known symbol), leading to undefined behavior. ## The `link_section` attribute @@ -75,9 +75,8 @@ The *`link_section` attribute* specifies the section of the object file that a [function] or [static]'s content will be placed into. It uses the [_MetaNameValueStr_] syntax to specify the section name. -This attribute is unsafe as using `link_section` allows users to place data -and code into sections of memory not expecting them, such as mutable data -into read-only areas. +This attribute is unsafe as it allows users to place data and code into sections +of memory not expecting them, such as mutable data into read-only areas. ```rust,no_run @@ -93,7 +92,8 @@ exported on a [function] or [static]. It uses the [_MetaNameValueStr_] syntax to specify the symbol name. This attribute is unsafe as a symbol with a custom name may collide with another -symbol with the same name (or a well-known symbol), leading to undefined behavior. +symbol with the same name (or with a well-known symbol), leading to undefined +behavior. ```rust #[export_name = "exported_symbol_name"] diff --git a/src/attributes.md b/src/attributes.md index a2ed37f..9bc82c3 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -33,9 +33,10 @@ Attributes other than macro attributes also allow the input to be an equals sign (`=`) followed by an expression. See the [meta item syntax](#meta-item-attribute-syntax) below for more details. -An attribute may be considered unsafe. Unsafe attributes must *satisfy* extra -safety conditions that cannot be checked by the compiler, and are specified -as the attribute wrapped in `unsafe(...)`, for instance, `#[unsafe(no_mangle)]`. +An attribute may be unsafe to apply. To avoid undefined behavior when using +these attributes, certain obligations that cannot be checked by the compiler +must be met. To assert these have been, the attribute is wrapped in +`unsafe(..)`, e.g. `#[unsafe(no_mangle)]`. The following attributes are unsafe: From 4a4db8eb99779da93f2de860aeae7940712ddb1f Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 22 Jul 2024 07:49:01 +0000 Subject: [PATCH 026/189] Fix grammar for unsafe attributes There were some errors in the formatting and the content of the grammar for unsafe attributes. Let's fix those. --- src/attributes.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index 9bc82c3..c05bfa0 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -3,14 +3,12 @@ > **Syntax**\ > _InnerAttribute_ :\ ->    `#` `!` `[` _Attr_ `]` ->    `#` `!` `[` `unsafe` `(` _Attr_ `)` `]` +>       `#` `!` `[` _Attr_ `]`\ +>    | `#` `!` `[` `unsafe` `(` _Attr_ `)` `]` > > _OuterAttribute_ :\ ->    `#` `[` _Attr_ `]` ->    `#` `[` `unsafe` `(` _Attr_ `)` `]` ->    `#` `!` `[` _Attr_ `]` ->    `#` `!` `[` `unsafe` `(` _Attr_ `)` `]` +>       `#` `[` _Attr_ `]`\ +>    | `#` `[` `unsafe` `(` _Attr_ `)` `]` > > _Attr_ :\ >    [_SimplePath_] _AttrInput_? From 5fd2cb56407c9ec4ad53c1b9c4f76595bd101507 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 22 Jul 2024 08:07:08 +0000 Subject: [PATCH 027/189] Add to unsafety section for unsafe attributes Let's describe unsafe attributes in the chapter on unsafety. --- src/unsafe-keyword.md | 10 ++++++++-- src/unsafety.md | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index df68a74..20aa1aa 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -1,10 +1,10 @@ # The `unsafe` keyword The `unsafe` keyword can occur in several different contexts: -unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), unsafe trait implementations (`unsafe impl`), and unsafe external blocks (`unsafe extern`). +unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), unsafe trait implementations (`unsafe impl`), unsafe external blocks (`unsafe extern`), and unsafe attributes (`#[unsafe(attr)]`). It plays several different roles, depending on where it is used and whether the `unsafe_op_in_unsafe_fn` lint is enabled: - it is used to mark code that *defines* extra safety conditions (`unsafe fn`, `unsafe trait`) -- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`], `unsafe extern`) +- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`], `unsafe extern`, `#[unsafe(attr)]`) The following discusses each of these cases. See the [keyword documentation][keyword] for some illustrative examples. @@ -62,3 +62,9 @@ Unsafe trait implementations are the logical dual to unsafe traits: where unsafe The programmer who declares an [external block] must assure that the signatures of the items contained within are correct. Failing to do so may lead to undefined behavior. That this obligation has been met is indicated by writing `unsafe extern`. [external block]: items/external-blocks.md + +## Unsafe attributes (`#[unsafe(attr)]`) + +An [unsafe attribute] is one that has extra safety conditions that must be upheld when using the attribute. The compiler cannot check whether these conditions have been upheld. To assert that they have been, these attributes must be wrapped in `unsafe(..)`, e.g. `#[unsafe(no_mangle)]`. + +[unsafe attribute]: attributes.md diff --git a/src/unsafety.md b/src/unsafety.md index 237a4bf..9383eba 100644 --- a/src/unsafety.md +++ b/src/unsafety.md @@ -12,6 +12,7 @@ Rust: - Calling an unsafe function (including an intrinsic or foreign function). - Implementing an [unsafe trait]. - Declaring an [`extern`] block. +- Applying an [unsafe attribute] to an item. [`extern`]: items/external-blocks.md [`union`]: items/unions.md @@ -19,3 +20,4 @@ Rust: [external]: items/external-blocks.md [raw pointer]: types/pointer.md [unsafe trait]: items/traits.md#unsafe-traits +[unsafe attribute]: attributes.md From e36508cadfd13a14d46c30710af56161b2131c3b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 24 Jul 2024 17:16:15 -0700 Subject: [PATCH 028/189] Fix the Attr grammar for unsafe attributes. The _Attr_ production is used for `cfg_attr` attribute and the `meta` macro fragment specifier, and those need to accept the new `unsafe` syntax. --- src/attributes.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index c05bfa0..f3ca917 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -3,15 +3,14 @@ > **Syntax**\ > _InnerAttribute_ :\ ->       `#` `!` `[` _Attr_ `]`\ ->    | `#` `!` `[` `unsafe` `(` _Attr_ `)` `]` +>    `#` `!` `[` _Attr_ `]` > > _OuterAttribute_ :\ ->       `#` `[` _Attr_ `]`\ ->    | `#` `[` `unsafe` `(` _Attr_ `)` `]` +>    `#` `[` _Attr_ `]` > > _Attr_ :\ ->    [_SimplePath_] _AttrInput_? +>       [_SimplePath_] _AttrInput_?\ +>    | `unsafe` `(` [_SimplePath_] _AttrInput_? `)` > > _AttrInput_ :\ >       [_DelimTokenTree_]\ From 39b9526e582fd71e5f6cfb0b6eb050b62ab6141b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 24 Jul 2024 17:16:23 -0700 Subject: [PATCH 029/189] Use `unsafe` in the unsafe attribute examples. This will be required in 2024. --- src/abi.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/abi.md b/src/abi.md index 47116f5..09ff20b 100644 --- a/src/abi.md +++ b/src/abi.md @@ -69,6 +69,11 @@ object file, similar to the [`used` attribute](#the-used-attribute). This attribute is unsafe as an unmangled symbol may collide with another symbol with the same name (or with a well-known symbol), leading to undefined behavior. +```rust +#[unsafe(no_mangle)] +extern "C" fn foo() {} +``` + ## The `link_section` attribute The *`link_section` attribute* specifies the section of the object file that a @@ -80,8 +85,8 @@ of memory not expecting them, such as mutable data into read-only areas. ```rust,no_run -#[no_mangle] -#[link_section = ".example_section"] +#[unsafe(no_mangle)] +#[unsafe(link_section = ".example_section")] pub static VAR1: u32 = 1; ``` @@ -96,7 +101,7 @@ symbol with the same name (or with a well-known symbol), leading to undefined behavior. ```rust -#[export_name = "exported_symbol_name"] +#[unsafe(export_name = "exported_symbol_name")] pub fn name_in_rust() { } ``` From e16450d891a419fe975d7ef8cf36e659134906ca Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 20 Aug 2024 05:09:24 +0000 Subject: [PATCH 030/189] Optimize a bit It's better to allocate for the smaller prefix that we're extracting than to allocate repeatedly for the tail items, especially as `split_off` doesn't shrink the capacity of what we go on to insert. --- mdbook-spec/src/std_links.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index 789518c..8f9da6b 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -55,6 +55,7 @@ pub fn std_links(book: &mut Book) { .captures_iter(&generated) .map(|cap| cap.get(1).unwrap().as_str()) .collect(); + let mut urls = &mut urls[..]; let expected_len: usize = chapter_links.values().map(|l| l.len()).sum(); if urls.len() != expected_len { eprintln!( @@ -67,9 +68,9 @@ pub fn std_links(book: &mut Book) { // Unflatten the urls list so that it is split back by chapter. let mut ch_urls: HashMap<&PathBuf, Vec<_>> = HashMap::new(); for (ch_path, links) in &chapter_links { - let rest = urls.split_off(links.len()); - ch_urls.insert(ch_path, urls); - urls = rest; + let xs; + (xs, urls) = urls.split_at_mut(links.len()); + ch_urls.insert(ch_path, xs.into()); } // Do this in two passes to deal with lifetimes. From a136907f85b298aacab568e1a619b16e68bc51cf Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 20 Aug 2024 05:14:09 +0000 Subject: [PATCH 031/189] Make some idiomatic tweaks --- mdbook-spec/src/std_links.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index 8f9da6b..d0b0179 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -86,7 +86,7 @@ pub fn std_links(book: &mut Book) { // Create a list of replacements to make in the raw markdown to point to the new url. let replacements = compute_replacements(&ch.content, &chapter_links[key], &ch_urls[key]); - let mut new_contents = ch.content.to_string(); + let mut new_contents = ch.content.clone(); for (md_link, url, range) in replacements { // Convert links to be relative so that links work offline and // with the linkchecker. @@ -130,7 +130,7 @@ struct Link<'a> { } /// Collects all markdown links that look like they might be standard library links. -fn collect_markdown_links<'a>(chapter: &'a Chapter) -> Vec> { +fn collect_markdown_links(chapter: &Chapter) -> Vec> { let mut opts = Options::empty(); opts.insert(Options::ENABLE_TABLES); opts.insert(Options::ENABLE_FOOTNOTES); @@ -294,7 +294,7 @@ fn compute_replacements<'a>( ) -> Vec<(&'a str, &'a str, Range)> { let mut replacements = Vec::new(); - for (url, link) in urls.into_iter().zip(links) { + for (url, link) in urls.iter().zip(links) { let Some(cap) = ANCHOR_URL.captures(url) else { eprintln!("error: could not find anchor in:\n{url}\nlink={link:#?}"); process::exit(1); From a34406aaf7cf2a914a436405058e86c813b94e33 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 10 Aug 2024 13:41:13 +0200 Subject: [PATCH 032/189] operator expressions: add &raw --- src/expressions.md | 4 ++-- src/expressions/operator-expr.md | 26 ++++++++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 208ac95..75c9834 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -146,7 +146,7 @@ A *value expression* is an expression that represents an actual value. The following contexts are *place expression* contexts: * The left operand of a [compound assignment] expression. -* The operand of a unary [borrow], [address-of][addr-of] or [dereference][deref] operator. +* The operand of a unary [borrow], [raw borrow][raw-borrow] or [dereference][deref] operator. * The operand of a field expression. * The indexed operand of an array indexing expression. * The operand of any [implicit borrow]. @@ -276,7 +276,7 @@ They are never allowed before: [assign]: expressions/operator-expr.md#assignment-expressions [borrow]: expressions/operator-expr.md#borrow-operators -[addr-of]: expressions/operator-expr.md#raw-address-of-operators +[raw-borrow]: expressions/operator-expr.md#raw-borrow-operators [comparison]: expressions/operator-expr.md#comparison-operators [compound assignment]: expressions/operator-expr.md#compound-assignment-expressions [deref]: expressions/operator-expr.md#the-dereference-operator diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 0601a86..ea39841 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -41,7 +41,9 @@ The following things are considered to be overflow: > **Syntax**\ > _BorrowExpression_ :\ >       (`&`|`&&`) [_Expression_]\ ->    | (`&`|`&&`) `mut` [_Expression_] +>    | (`&`|`&&`) `mut` [_Expression_]\ +>    | (`&`|`&&`) `raw` `const` [_Expression_]\ +>    | (`&`|`&&`) `raw` `mut` [_Expression_] The `&` (shared borrow) and `&mut` (mutable borrow) operators are unary prefix operators. When applied to a [place expression], this expressions produces a reference (pointer) to the location that the value refers to. @@ -79,20 +81,18 @@ let a = && && mut 10; let a = & & & & mut 10; ``` -### Raw address-of operators +### Raw borrow operators -Related to the borrow operators are the *raw address-of operators*, which do not have first-class syntax, but are exposed via the macros [`ptr::addr_of!(expr)`][addr_of] and [`ptr::addr_of_mut!(expr)`][addr_of_mut]. -The expression `expr` is evaluated in place expression context. -`ptr::addr_of!(expr)` then creates a const raw pointer of type `*const T` to the given place, and `ptr::addr_of_mut!(expr)` creates a mutable raw pointer of type `*mut T`. +`&raw const` and `&raw mut` are the *raw borrow operators*. +The operand expression of these operators is evaluated in place expression context. +`&raw const expr` then creates a const raw pointer of type `*const T` to the given place, and `&raw mut expr` creates a mutable raw pointer of type `*mut T`. -The raw address-of operators must be used instead of a borrow operator whenever the place expression could evaluate to a place that is not properly aligned or does not store a valid value as determined by its type, or whenever creating a reference would introduce incorrect aliasing assumptions. -In those situations, using a borrow operator would cause [undefined behavior] by creating an invalid reference, but a raw pointer may still be constructed using an address-of operator. +The raw borrow operators must be used instead of a borrow operator whenever the place expression could evaluate to a place that is not properly aligned or does not store a valid value as determined by its type, or whenever creating a reference would introduce incorrect aliasing assumptions. +In those situations, using a borrow operator would cause [undefined behavior] by creating an invalid reference, but a raw pointer may still be constructed. The following is an example of creating a raw pointer to an unaligned place through a `packed` struct: ```rust -use std::ptr; - #[repr(packed)] struct Packed { f1: u8, @@ -101,14 +101,14 @@ struct Packed { let packed = Packed { f1: 1, f2: 2 }; // `&packed.f2` would create an unaligned reference, and thus be undefined behavior! -let raw_f2 = ptr::addr_of!(packed.f2); +let raw_f2 = &raw const packed.f2; assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); ``` The following is an example of creating a raw pointer to a place that does not contain a valid value: ```rust -use std::{ptr, mem::MaybeUninit}; +use std::mem::MaybeUninit; struct Demo { field: bool, @@ -117,7 +117,7 @@ struct Demo { let mut uninit = MaybeUninit::::uninit(); // `&uninit.as_mut().field` would create a reference to an uninitialized `bool`, // and thus be undefined behavior! -let f1_ptr = unsafe { ptr::addr_of_mut!((*uninit.as_mut_ptr()).field) }; +let f1_ptr = unsafe { &raw mut (*uninit.as_mut_ptr()).field }; unsafe { f1_ptr.write(true); } let init = unsafe { uninit.assume_init() }; ``` @@ -674,8 +674,6 @@ See [this test] for an example of using this dependency. [Function pointer]: ../types/function-pointer.md [Function item]: ../types/function-item.md [undefined behavior]: ../behavior-considered-undefined.md -[addr_of]: std::ptr::addr_of -[addr_of_mut]: std::ptr::addr_of_mut [_BorrowExpression_]: #borrow-operators [_DereferenceExpression_]: #the-dereference-operator From feea14335f77a4f9951983f4cdca468e88379733 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 12 Aug 2024 10:44:07 +0200 Subject: [PATCH 033/189] use &raw instead of addr_of macros --- src/behavior-considered-undefined.md | 2 +- src/items/static-items.md | 2 +- src/type-layout.md | 4 ++-- src/types/pointer.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 14d8ede..e7fa1a0 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -102,7 +102,7 @@ the pointer that was dereferenced, *not* the type of the field that is being accessed. Note that a place based on a misaligned pointer only leads to undefined behavior -when it is loaded from or stored to. `addr_of!`/`addr_of_mut!` on such a place +when it is loaded from or stored to. `&raw const`/`&raw mut` on such a place is allowed. `&`/`&mut` on a place requires the alignment of the field type (or else the program would be "producing an invalid value"), which generally is a less restrictive requirement than being based on an aligned pointer. Taking a diff --git a/src/items/static-items.md b/src/items/static-items.md index f00f1aa..f688a90 100644 --- a/src/items/static-items.md +++ b/src/items/static-items.md @@ -117,7 +117,7 @@ unsafe fn bump_levels_unsafe() -> u32 { // must still guard against concurrent access. fn bump_levels_safe() -> u32 { unsafe { - return atomic_add(std::ptr::addr_of_mut!(LEVELS), 1); + return atomic_add(&raw mut LEVELS, 1); } } ``` diff --git a/src/type-layout.md b/src/type-layout.md index 8b1a689..b91674f 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -575,9 +575,9 @@ was wrapped in a newtype `struct` with the same `align` modifier. > println!("{}", {e.f2}); > // Or if you need a pointer, use the unaligned methods for reading and writing > // instead of dereferencing the pointer directly. -> let ptr: *const u16 = std::ptr::addr_of!(e.f2); +> let ptr: *const u16 = &raw const e.f2; > let value = unsafe { ptr.read_unaligned() }; -> let mut_ptr: *mut u16 = std::ptr::addr_of_mut!(e.f2); +> let mut_ptr: *mut u16 = &raw mut e.f2; > unsafe { mut_ptr.write_unaligned(3) } > ``` diff --git a/src/types/pointer.md b/src/types/pointer.md index a1ec509..7299ce7 100644 --- a/src/types/pointer.md +++ b/src/types/pointer.md @@ -44,7 +44,7 @@ they exist to support interoperability with foreign code, and writing performanc When comparing raw pointers they are compared by their address, rather than by what they point to. When comparing raw pointers to [dynamically sized types] they also have their additional data compared. -Raw pointers can be created directly using [`core::ptr::addr_of!`] for `*const` pointers and [`core::ptr::addr_of_mut!`] for `*mut` pointers. +Raw pointers can be created directly using `&raw const` for `*const` pointers and `&raw mut` for `*mut` pointers. ## Smart Pointers From a229d145dfcca05122385c722766a1f1d411ece0 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 18 Aug 2024 12:40:15 +0200 Subject: [PATCH 034/189] markdown anchor tweaks --- src/expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 75c9834..1ee015f 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -146,7 +146,7 @@ A *value expression* is an expression that represents an actual value. The following contexts are *place expression* contexts: * The left operand of a [compound assignment] expression. -* The operand of a unary [borrow], [raw borrow][raw-borrow] or [dereference][deref] operator. +* The operand of a unary [borrow], [raw borrow] or [dereference][deref] operator. * The operand of a field expression. * The indexed operand of an array indexing expression. * The operand of any [implicit borrow]. @@ -276,7 +276,6 @@ They are never allowed before: [assign]: expressions/operator-expr.md#assignment-expressions [borrow]: expressions/operator-expr.md#borrow-operators -[raw-borrow]: expressions/operator-expr.md#raw-borrow-operators [comparison]: expressions/operator-expr.md#comparison-operators [compound assignment]: expressions/operator-expr.md#compound-assignment-expressions [deref]: expressions/operator-expr.md#the-dereference-operator @@ -294,6 +293,7 @@ They are never allowed before: [Mutable `static` items]: items/static-items.md#mutable-statics [scrutinee]: glossary.md#scrutinee [promoted]: destructors.md#constant-promotion +[raw borrow]: expressions/operator-expr.md#raw-borrow-operators [slice]: types/slice.md [statement]: statements.md [static variables]: items/static-items.md From d89491c5282f37ebde9a3236ef7d4f7f7b9f5f15 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 2 Aug 2024 14:39:50 +0200 Subject: [PATCH 035/189] bytes inside implicitly const-promoted expressions are immutable --- src/behavior-considered-undefined.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index bee5010..e9e89d2 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -49,7 +49,7 @@ Please read the [Rustonomicon] before writing unsafe code. All this also applies when values of these types are passed in a (nested) field of a compound type, but not behind pointer indirections. -* Mutating immutable bytes. All bytes inside a [`const`] item are immutable. +* Mutating immutable bytes. All bytes inside a [`const`] item or within an implicitly [const-promoted] expression are immutable. The bytes owned by an immutable binding or immutable `static` are immutable, unless those bytes are part of an [`UnsafeCell`]. Moreover, the bytes [pointed to] by a shared reference, including transitively through other references (both shared and mutable) and `Box`es, are immutable; transitivity includes those references stored in fields of compound types. @@ -189,3 +189,4 @@ reading uninitialized memory is permitted are inside `union`s and in "padding" [project-field]: expressions/field-expr.md [project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions [project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions +[const-promoted]: destructors.md#constant-promotion From ffbd67d7377ebbc57fb686faa1bc255b2231741d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 21:00:41 +0200 Subject: [PATCH 036/189] clarify limitations on type system consts --- src/const_eval.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/const_eval.md b/src/const_eval.md index a494b5c..e3cefa5 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -63,7 +63,9 @@ A _const context_ is one of the following: Const contexts that are used as parts of types (array type and repeat length expressions as well as const generic arguments) can only make restricted use of -surrounding generic type and lifetime parameters. +surrounding generic parameters: such an expression must either be a single bare +const generic parameter, or an arbitrary expression not making use of any +generics. ## Const Functions From d70cd557af2b4dc6458ff0083faabe731fba60f5 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 19:47:17 -0400 Subject: [PATCH 037/189] Make requested and CI stylistic changes to destructors.md identifiers --- src/destructors.md | 55 +++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/destructors.md b/src/destructors.md index 8e4873a..4fc947b 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -1,8 +1,6 @@ # Destructors -r[destructors] - -r[destructors.general] +r[destructors.intro] When an [initialized] [variable] or [temporary] goes out of [scope](#drop-scopes), its *destructor* is run, or it is *dropped*. [Assignment] also runs the destructor of its left-hand operand, if it's initialized. If a @@ -62,78 +60,77 @@ core::mem::forget(partial_move.1); ## Drop scopes -r[destructor.scope] - +r[destructors.scope] -r[destructor.scope.general] +r[destructors.scope.intro] Each variable or temporary is associated to a *drop scope*. When control flow leaves a drop scope all variables associated to that scope are dropped in reverse order of declaration (for variables) or creation (for temporaries). -r[destructor.scope.desugaring] +r[destructors.scope.desugaring] Drop scopes are determined after replacing [`for`], [`if let`], and [`while let`] expressions with the equivalent expressions using [`match`]. -r[destructor.scope.operators] +r[destructors.scope.operators] Overloaded operators are not distinguished from built-in operators and [binding modes] are not considered. -r[destructor.scope.list] +r[destructors.scope.list] Given a function, or closure, there are drop scopes for: -r[destructor.scope.function] +r[destructors.scope.function] * The entire function -r[destructor.scope.statement] +r[destructors.scope.statement] * Each [statement] -r[destructor.scope.expression] +r[destructors.scope.expression] * Each [expression] -r[destructor.scope.block] +r[destructors.scope.block] * Each block, including the function body * In the case of a [block expression], the scope for the block and the expression are the same scope. -r[destructor.scope.match-arm] +r[destructors.scope.match-arm] * Each arm of a `match` expression -r[destructor.scope.nesting] +r[destructors.scope.nesting] Drop scopes are nested within one another as follows. When multiple scopes are left at once, such as when returning from a function, variables are dropped from the inside outwards. -r[destructor.scope.nesting.function] +r[destructors.scope.nesting.function] * The entire function scope is the outer most scope. -r[destructor.scope.nesting.function-body] +r[destructors.scope.nesting.function-body] * The function body block is contained within the scope of the entire function. -r[destructor.scope.nesting.expr-statement] +r[destructors.scope.nesting.expr-statement] * The parent of the expression in an expression statement is the scope of the statement. -r[destructor.scope.nesting.let-initializer] +r[destructors.scope.nesting.let-initializer] * The parent of the initializer of a [`let` statement] is the `let` statement's scope. -r[destructor.scope.nesting.statement] +r[destructors.scope.nesting.statement] * The parent of a statement scope is the scope of the block that contains the statement. -r[destructor.scope.nesting.match-guard] +r[destructors.scope.nesting.match-guard] * The parent of the expression for a `match` guard is the scope of the arm that the guard is for. -r[destructor.scope.nesting.match-arm] +r[destructors.scope.nesting.match-arm] * The parent of the expression after the `=>` in a `match` expression is the scope of the arm that it's in. -r[destructor.scope.nesting.match] +r[destructors.scope.nesting.match] * The parent of the arm scope is the scope of the `match` expression that it belongs to. -r[destructor.scope.nesting.other] +r[destructors.scope.nesting.other] * The parent of all other scopes is the scope of the immediately enclosing expression. @@ -167,9 +164,9 @@ patterns_in_parameters( ### Scopes of local variables -r[destructor.scope.bindings] +r[destructors.scope.bindings] -r[destructor.scope.bindings.general] +r[destructors.scope.bindings.intro] Local variables declared in a `let` statement are associated to the scope of the block that contains the `let` statement. Local variables declared in a `match` expression are associated to the arm scope of the `match` arm that they @@ -197,13 +194,12 @@ unspecified pattern will be used to determine the drop order. r[destructors.scope.temporary] - -r[destructor.scope.temporary.general] +r[destructors.scope.temporary.intro] The *temporary scope* of an expression is the scope that is used for the temporary variable that holds the result of that expression when used in a [place context], unless it is [promoted]. -r[destructor.scope.temporary.enclosing] +r[destructors.scope.temporary.enclosing] Apart from lifetime extension, the temporary scope of an expression is the smallest scope that contains the expression and is one of the following: @@ -341,7 +337,6 @@ temporary scope. r[destructors.scope.lifetime-extension.patterns] - r[destructors.scope.lifetime-extension.patterns.extending] An *extending pattern* is either From 880b13214ce5503f2b54cecda8ef96c344cc598c Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 19:51:17 -0400 Subject: [PATCH 038/189] Remove double line break from comments.md --- src/comments.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/comments.md b/src/comments.md index 753051f..9b7b6cd 100644 --- a/src/comments.md +++ b/src/comments.md @@ -1,6 +1,5 @@ # Comments - r[comments.lexical] > **Lexer**\ From 2fb357b5f5e0c02444470248f35ce4bf6e5b35bb Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 21:30:23 -0400 Subject: [PATCH 039/189] Add identifier syntax to identifiers.md --- src/identifiers.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/identifiers.md b/src/identifiers.md index c760f68..66b9d1a 100644 --- a/src/identifiers.md +++ b/src/identifiers.md @@ -1,5 +1,8 @@ # Identifiers +r[ident] + +r[ident.syntax] > **Lexer:**\ > IDENTIFIER_OR_KEYWORD :\ >       XID_Start XID_Continue\*\ @@ -13,6 +16,7 @@ > NON_KEYWORD_IDENTIFIER | RAW_IDENTIFIER +r[ident.unicode] Identifiers follow the specification in [Unicode Standard Annex #31][UAX31] for Unicode version 15.0, with the additions described below. Some examples of identifiers: * `foo` @@ -21,6 +25,7 @@ Identifiers follow the specification in [Unicode Standard Annex #31][UAX31] for * `Москва` * `東京` +r[ident.profile] The profile used from UAX #31 is: * Start := [`XID_Start`], plus the underscore character (U+005F) @@ -31,28 +36,47 @@ with the additional constraint that a single underscore character is not an iden > **Note**: Identifiers starting with an underscore are typically used to indicate an identifier that is intentionally unused, and will silence the unused warning in `rustc`. +r[ident.keyword] Identifiers may not be a [strict] or [reserved] keyword without the `r#` prefix described below in [raw identifiers](#raw-identifiers). +r[ident.zero-width-chars] Zero width non-joiner (ZWNJ U+200C) and zero width joiner (ZWJ U+200D) characters are not allowed in identifiers. +r[ident.ascii-limitations] Identifiers are restricted to the ASCII subset of [`XID_Start`] and [`XID_Continue`] in the following situations: +r[ident.ascii-extern-crate] * [`extern crate`] declarations + +r[ident.ascii-extern-prelude] * External crate names referenced in a [path] + +r[ident.ascii-outlined-module] * [Module] names loaded from the filesystem without a [`path` attribute] + +r[ident.ascii-no_mangle] * [`no_mangle`] attributed items + +r[ident.ascii-extern-item] * Item names in [external blocks] ## Normalization +r[ident.normalize] + Identifiers are normalized using Normalization Form C (NFC) as defined in [Unicode Standard Annex #15][UAX15]. Two identifiers are equal if their NFC forms are equal. [Procedural][proc-macro] and [declarative][mbe] macros receive normalized identifiers in their input. ## Raw identifiers +r[ident.raw] + +r[ident.raw.intro] A raw identifier is like a normal identifier, but prefixed by `r#`. (Note that the `r#` prefix is not included as part of the actual identifier.) + +r[ident.raw.allowed] Unlike a normal identifier, a raw identifier may be any strict or reserved keyword except the ones listed above for `RAW_IDENTIFIER`. From 4f7a36001ad28429e079fe002a1c5761e51b1105 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 21:33:55 -0400 Subject: [PATCH 040/189] Add spec identifier syntax to input-format.md --- src/input-format.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/input-format.md b/src/input-format.md index 8d921bf..79121fe 100644 --- a/src/input-format.md +++ b/src/input-format.md @@ -1,26 +1,41 @@ # Input format +r[input] + +r[input.intro] This chapter describes how a source file is interpreted as a sequence of tokens. See [Crates and source files] for a description of how programs are organised into files. ## Source encoding +r[input.encoding] + +r[input.encoding.utf8] Each source file is interpreted as a sequence of Unicode characters encoded in UTF-8. + +r[input.encoding.invalid] It is an error if the file is not valid UTF-8. ## Byte order mark removal +r[input.byte-order-mark] + If the first character in the sequence is `U+FEFF` ([BYTE ORDER MARK]), it is removed. ## CRLF normalization +r[input.crlf] + Each pair of characters `U+000D` (CR) immediately followed by `U+000A` (LF) is replaced by a single `U+000A` (LF). Other occurrences of the character `U+000D` (CR) are left in place (they are treated as [whitespace]). ## Shebang removal +r[input.shebang] + +r[input.shebang.intro] If the remaining sequence begins with the characters `#!`, the characters up to and including the first `U+000A` (LF) are removed from the sequence. For example, the first line of the following file would be ignored: @@ -34,6 +49,7 @@ fn main() { } ``` +r[input.shebang.inner-attribute] As an exception, if the `#!` characters are followed (ignoring intervening [comments] or [whitespace]) by a `[` token, nothing is removed. This prevents an [inner attribute] at the start of a source file being removed. @@ -41,8 +57,9 @@ This prevents an [inner attribute] at the start of a source file being removed. ## Tokenization -The resulting sequence of characters is then converted into tokens as described in the remainder of this chapter. +r[input.tokenization] +The resulting sequence of characters is then converted into tokens as described in the remainder of this chapter. [`include!`]: ../std/macro.include.md [`include_bytes!`]: ../std/macro.include_bytes.md From e3d3c5b7d64199874b28b67d93843b281f253147 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 22 Aug 2024 08:49:43 -0700 Subject: [PATCH 041/189] Be consistent about how "Edition differences" is capitalized The existing text was inconsistent with whether or not the "d" was capitalized. This goes the route of using a lowercase "d" to match the style of using sentence-case for headings. --- docs/authoring.md | 2 +- src/expressions/method-call-expr.md | 2 +- src/introduction.md | 4 ++-- src/items/associated-items.md | 2 +- src/macros-by-example.md | 6 +++--- src/names/preludes.md | 4 ++-- src/paths.md | 2 +- src/patterns.md | 2 +- src/tokens.md | 6 +++--- src/types/trait-object.md | 4 ++-- src/visibility-and-privacy.md | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/authoring.md b/docs/authoring.md index a01c8a5..74c9bc9 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -154,4 +154,4 @@ The reference does not document which targets exist, or the properties of specif ### Editions -The main text and flow should document only the current edition. Whenever there is a difference between editions, the differences should be called out with an "Edition Differences" block. +The main text and flow should document only the current edition. Whenever there is a difference between editions, the differences should be called out with an "Edition differences" block. diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index 7f21c49..ca7f185 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -66,7 +66,7 @@ Once a method is looked up, if it can't be called for one (or more) of those rea If a step is reached where there is more than one possible method, such as where generic methods or traits are considered the same, then it is a compiler error. These cases require a [disambiguating function call syntax] for method and function invocation. -> **Edition Differences**: Before the 2021 edition, during the search for visible methods, if the candidate receiver type is an [array type], methods provided by the standard library [`IntoIterator`] trait are ignored. +> **Edition differences**: Before the 2021 edition, during the search for visible methods, if the candidate receiver type is an [array type], methods provided by the standard library [`IntoIterator`] trait are ignored. > > The edition used for this purpose is determined by the token representing the method name. > diff --git a/src/introduction.md b/src/introduction.md index 7f01096..2bf5beb 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -82,9 +82,9 @@ These conventions are documented here. An *example term* is an example of a term being defined. -* Differences in the language by which edition the crate is compiled under are in a blockquote that start with the words "Edition Differences:" in **bold**. +* Differences in the language by which edition the crate is compiled under are in a blockquote that start with the words "Edition differences:" in **bold**. - > **Edition Differences**: In the 2015 edition, this syntax is valid that is disallowed as of the 2018 edition. + > **Edition differences**: In the 2015 edition, this syntax is valid that is disallowed as of the 2018 edition. * Notes that contain useful information about the state of the book or point out useful, but mostly out of scope, information are in blockquotes that start with the word "Note:" in **bold**. diff --git a/src/items/associated-items.md b/src/items/associated-items.md index 2401127..c4e7a19 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -189,7 +189,7 @@ let circle_shape = Circle::new(); let bounding_box = circle_shape.bounding_box(); ``` -> **Edition Differences**: In the 2015 edition, it is possible to declare trait +> **Edition differences**: In the 2015 edition, it is possible to declare trait > methods with anonymous parameters (e.g. `fn foo(u8)`). This is deprecated and > an error as of the 2018 edition. All parameters must have an argument name. diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 69a236d..e95cd2e 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -148,7 +148,7 @@ the `expr` fragment specifier. However, `_` is matched by the `expr` fragment specifier when it appears as a subexpression. For the same reason, a standalone [const block] is not matched but it is matched when appearing as a subexpression. -> **Edition Differences**: Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]). +> **Edition differences**: Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]). > > Before the 2021 edition, they match exactly the same fragments as `pat_param` (that is, they accept [_PatternNoTopAlt_]). > @@ -421,7 +421,7 @@ macro_rules! call_foo { fn foo() {} ``` -> **Version & Edition Differences**: Prior to Rust 1.30, `$crate` and +> **Version & Edition differences**: Prior to Rust 1.30, `$crate` and > `local_inner_macros` (below) were unsupported. They were added alongside > path-based imports of macros (described above), to ensure that helper macros > did not need to be manually imported by users of a macro-exporting crate. @@ -475,7 +475,7 @@ Matchers like `$i:expr,` or `$i:expr;` would be legal, however, because `,` and `ident`, `ty`, or `path` fragment specifier. * All other fragment specifiers have no restrictions. -> **Edition Differences**: Before the 2021 edition, `pat` may also be followed by `|`. +> **Edition differences**: Before the 2021 edition, `pat` may also be followed by `|`. When repetitions are involved, then the rules apply to every possible number of expansions, taking separators into account. This means: diff --git a/src/names/preludes.md b/src/names/preludes.md index 745b290..7e6b7d4 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -44,7 +44,7 @@ new_name`, then the symbol `new_name` is instead added to the prelude. The [`core`] crate is always added to the extern prelude. The [`std`] crate is added as long as the [`no_std` attribute] is not specified in the crate root. -> **Edition Differences**: In the 2015 edition, crates in the extern prelude +> **Edition differences**: In the 2015 edition, crates in the extern prelude > cannot be referenced via [use declarations], so it is generally standard > practice to include `extern crate` declarations to bring them into scope. > @@ -132,7 +132,7 @@ module or any of its descendants. This attribute does not affect the [language prelude]. -> **Edition Differences**: In the 2015 edition, the `no_implicit_prelude` +> **Edition differences**: 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. diff --git a/src/paths.md b/src/paths.md index 525a325..1274810 100644 --- a/src/paths.md +++ b/src/paths.md @@ -166,7 +166,7 @@ Paths starting with `::` are considered to be *global paths* where the segments start being resolved from a place which differs based on edition. Each identifier in the path must resolve to an item. -> **Edition Differences**: In the 2015 Edition, identifiers resolve from the "crate root" +> **Edition differences**: In the 2015 Edition, identifiers resolve from the "crate root" > (`crate::` in the 2018 edition), which contains a variety of different items, including > external crates, default crates such as `std` or `core`, and items in the top level of > the crate (including `use` imports). diff --git a/src/patterns.md b/src/patterns.md index 0f186bf..479bb62 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -533,7 +533,7 @@ For example, `0u8..=255u8` is irrefutable. The range of values for an integer type is the closed range from its minimum to maximum value. The range of values for a `char` type are precisely those ranges containing all Unicode Scalar Values: `'\u{0000}'..='\u{D7FF}'` and `'\u{E000}'..='\u{10FFFF}'`. -> **Edition Differences**: Before the 2021 edition, range patterns with both a lower and upper bound may also be written using `...` in place of `..=`, with the same meaning. +> **Edition differences**: Before the 2021 edition, range patterns with both a lower and upper bound may also be written using `...` in place of `..=`, with the same meaning. ## Reference patterns diff --git a/src/tokens.md b/src/tokens.md index aeafe4b..d94464f 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -375,7 +375,7 @@ c"\u{00E6}"; c"\xC3\xA6"; ``` -> **Edition Differences**: C string literals are accepted in the 2021 edition or +> **Edition differences**: C string literals are accepted in the 2021 edition or > later. In earlier additions the token `c""` is lexed as `c ""`. #### Raw C string literals @@ -400,7 +400,7 @@ encoding. The characters `U+0022` (double-quote) (except when followed by at least as many `U+0023` (`#`) characters as were used to start the raw C string literal) or `U+005C` (`\`) do not have any special meaning. -> **Edition Differences**: Raw C string literals are accepted in the 2021 +> **Edition differences**: Raw C string literals are accepted in the 2021 > edition or later. In earlier additions the token `cr""` is lexed as `cr ""`, > and `cr#""#` is lexed as `cr #""#` (which is non-grammatical). @@ -735,7 +735,7 @@ Note that raw identifiers, raw string literals, and raw byte string literals may Similarly the `r`, `b`, `br`, `c`, and `cr` prefixes used in raw string literals, byte literals, byte string literals, raw byte string literals, C string literals, and raw C string literals are not interpreted as reserved prefixes. -> **Edition Differences**: Starting with the 2021 edition, reserved prefixes are reported as an error by the lexer (in particular, they cannot be passed to macros). +> **Edition differences**: Starting with the 2021 edition, reserved prefixes are reported as an error by the lexer (in particular, they cannot be passed to macros). > > Before the 2021 edition, reserved prefixes are accepted by the lexer and interpreted as multiple tokens (for example, one token for the identifier or keyword, followed by a `#` token). > diff --git a/src/types/trait-object.md b/src/types/trait-object.md index 3526b7a..5b8541f 100644 --- a/src/types/trait-object.md +++ b/src/types/trait-object.md @@ -31,13 +31,13 @@ For example, given a trait `Trait`, the following are all trait objects: * `dyn 'static + Trait`. * `dyn (Trait)` -> **Edition Differences**: Before the 2021 edition, the `dyn` keyword may be +> **Edition differences**: Before the 2021 edition, the `dyn` keyword may be > omitted. > > Note: For clarity, it is recommended to always use the `dyn` keyword on your > trait objects unless your codebase supports compiling with Rust 1.26 or lower. -> **Edition Differences**: In the 2015 edition, if the first bound of the +> **Edition differences**: In the 2015 edition, if the first bound of the > trait object is a path that starts with `::`, then the `dyn` will be treated > as a part of the path. The first path can be put in parenthesis to get > around this. As such, if you want a trait object with the trait diff --git a/src/visibility-and-privacy.md b/src/visibility-and-privacy.md index 67fd133..5ccf8b4 100644 --- a/src/visibility-and-privacy.md +++ b/src/visibility-and-privacy.md @@ -156,7 +156,7 @@ follows: - `pub(self)` makes an item visible to the current module. This is equivalent to `pub(in self)` or not using `pub` at all. -> **Edition Differences**: Starting with the 2018 edition, paths for +> **Edition differences**: Starting with the 2018 edition, paths for > `pub(in path)` must start with `crate`, `self`, or `super`. The 2015 edition > may also use paths starting with `::` or modules from the crate root. From 06dda7d0d6f36ec187575929652a81368ed81bc9 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 23 Aug 2024 04:43:08 +0000 Subject: [PATCH 042/189] Remove stray newline --- src/destructors.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/destructors.md b/src/destructors.md index 4fc947b..9c6819e 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -313,7 +313,6 @@ r[destructors.scope.lifetime-extension] > change. This is describing the current behavior only. r[destructors.scope.lifetime-extension.let] - The temporary scopes for expressions in `let` statements are sometimes *extended* to the scope of the block containing the `let` statement. This is done when the usual temporary scope would be too small, based on certain From cadfc4a1e72f6bb58bd7cfef5a3ae8ad6ba98e1b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 26 Aug 2024 11:27:50 -0700 Subject: [PATCH 043/189] Sync denied lints with upstream This synchronizes the lints in mdbook-spec that are denied in rust-lang/rust. This unblocks updating the books. --- mdbook-spec/src/lib.rs | 2 ++ mdbook-spec/src/std_links.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index ef1d565..1a8a919 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(rust_2018_idioms, unused_lifetimes)] + use mdbook::book::{Book, Chapter}; use mdbook::errors::Error; use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext}; diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs index d0b0179..28ca6ba 100644 --- a/mdbook-spec/src/std_links.rs +++ b/mdbook-spec/src/std_links.rs @@ -145,7 +145,7 @@ fn collect_markdown_links(chapter: &Chapter) -> Vec> { // Broken links are collected so that you can write something like // `[std::option::Option]` which in pulldown_cmark's eyes is a broken // link. However, that is the normal syntax for rustdoc. - let broken_link = |broken_link: BrokenLink| { + let broken_link = |broken_link: BrokenLink<'_>| { broken_links.push(Link { link_type: broken_link.link_type, // Necessary due to lifetime issues. @@ -205,7 +205,7 @@ fn collect_markdown_links(chapter: &Chapter) -> Vec> { /// generate intra-doc links on them. /// /// The output will be in the given `tmp` directory. -fn run_rustdoc(tmp: &TempDir, chapter_links: &HashMap<&PathBuf, Vec>) { +fn run_rustdoc(tmp: &TempDir, chapter_links: &HashMap<&PathBuf, Vec>>) { let src_path = tmp.path().join("a.rs"); // Allow redundant since there could some in-scope things that are // technically not necessary, but we don't care about (like From 6c91560b92c10c4e1af5c6bbb59c5eb130a7e1e1 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 27 Aug 2024 21:07:09 +0200 Subject: [PATCH 044/189] const_eval: update for const_mut_refs and const_refs_to_cell stabilization --- src/const_eval.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/const_eval.md b/src/const_eval.md index e3cefa5..dfcb61b 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -38,8 +38,11 @@ to be run. * [Closure expressions] which don't capture variables from the environment. * Built-in [negation], [arithmetic], [logical], [comparison] or [lazy boolean] operators used on integer and floating point types, `bool`, and `char`. -* Shared [borrow]s, except if applied to a type with [interior mutability]. -* The [dereference operator] except for raw pointers. +* All forms of [borrow]s, including raw borrows, with one limitation: + mutable borrows and shared borrows to values with interior mutability + are only allowed to refer to *transient* places. A place is *transient* + if it will be deallocated before the end of evaluating the current constant item. +* The [dereference operator]. * [Grouped] expressions. * [Cast] expressions, except * pointer to address casts and From 1e24d6841768e54e6f46a99ab42adf6fc5eb67cb Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 2 May 2023 12:16:16 +0000 Subject: [PATCH 045/189] Update enum.md Haskell uses data. OCaml and F# do use type, and SML does use datatype. There is no "data" in any ML that I know. --- src/types/enum.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/enum.md b/src/types/enum.md index 8f81fb1..1ee6fc6 100644 --- a/src/types/enum.md +++ b/src/types/enum.md @@ -16,7 +16,7 @@ Enum types cannot be denoted *structurally* as types, but must be denoted by named reference to an [`enum` item]. [^enumtype]: The `enum` type is analogous to a `data` constructor declaration in - ML, or a *pick ADT* in Limbo. + Haskell, or a *pick ADT* in Limbo. [`enum` item]: ../items/enumerations.md [struct expression]: ../expressions/struct-expr.md From 903ad38bb93612f975cce8e6675b082cb14db40b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 07:39:33 +0200 Subject: [PATCH 046/189] talk about const contexts, not const items --- src/const_eval.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/const_eval.md b/src/const_eval.md index dfcb61b..eca2530 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -41,7 +41,7 @@ to be run. * All forms of [borrow]s, including raw borrows, with one limitation: mutable borrows and shared borrows to values with interior mutability are only allowed to refer to *transient* places. A place is *transient* - if it will be deallocated before the end of evaluating the current constant item. + if its lifetime is strictly contained inside the current [const context]. * The [dereference operator]. * [Grouped] expressions. * [Cast] expressions, except @@ -52,6 +52,7 @@ to be run. * [if], [`if let`] and [match] expressions. ## Const context +[const context]: #const-context A _const context_ is one of the following: From c89cb2c8dcc127766ef4bc407f1b64e864399dae Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 13:49:47 -0700 Subject: [PATCH 047/189] Add a prefix to rule HTML IDs This adds the `r-` prefix to HTML IDs generated for rule names. This fixes a problem where the HTML IDs may conflict with existing markdown headers. For example, `## Crate` conflicts with `r[crate]`. This is done with the expectation that no headers will start with just the letter "r". --- mdbook-spec/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 1a8a919..37fa815 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -84,8 +84,8 @@ impl Spec { } } format!( - "

    \ - [{rule_id}]\ + "\n" ) }) @@ -104,7 +104,7 @@ impl Spec { .iter() .map(|(rule_id, (_, path))| { let relative = pathdiff::diff_paths(path, current_path).unwrap(); - format!("[{rule_id}]: {}#{rule_id}\n", relative.display()) + format!("[{rule_id}]: {}#r-{rule_id}\n", relative.display()) }) .collect(); format!( From c43a70ba7708c3ac128d56d4a7e78a07d41b5a5e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 14:09:12 -0700 Subject: [PATCH 048/189] Add a description of rule identifiers --- src/introduction.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/introduction.md b/src/introduction.md index 2bf5beb..6aae41b 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -120,6 +120,15 @@ These conventions are documented here. See [Notation] for more detail. +* Rule identifiers appear before each language rule enclosed in square brackets. These identifiers provide a way to refer to a specific rule in the language. The rule identifier uses periods to separate sections from most general to most specific ([destructors.scope.nesting.function-body] for example). + + The rule name can be clicked to link to that rule. + +r[example.rule.label] + + > [!WARNING] + > The organization of the rules is currently in flux. For the time being, these identifier names are not stable between releases, and links to these rules may fail if they are changed. We intend to stabilize these once the organization has settled so that links to the rule names will not break between releases. + ## Contributing We welcome contributions of all kinds. From 4722ccbcf31cd922e1167319e9b0bbf3fb79bb72 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 17:13:17 -0700 Subject: [PATCH 049/189] Allow admonition blockquotes with blank lines This fixes an issue where if an admonition blockquote had multiple paragraphs, it would incorrectly interpret it as multiple blockquotes, and break the formatting. The problem is that the regex was expecting at least one space after the `>`. I vaguely recall doing this intentionally, but I don't remember now why I did it this way, and I can't find any problems with this approach. --- mdbook-spec/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 1a8a919..0c3cb4d 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -19,7 +19,7 @@ static RULE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)^r\[([^]]+)]$").unwr /// The Regex for the syntax for blockquotes that have a specific CSS class, /// like `> [!WARNING]`. static ADMONITION_RE: Lazy = Lazy::new(|| { - Regex::new(r"(?m)^ *> \[!(?[^]]+)\]\n(?
    (?: *> .*\n)+)").unwrap() + Regex::new(r"(?m)^ *> \[!(?[^]]+)\]\n(?
    (?: *>.*\n)+)").unwrap() }); pub fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> { From a65b9a13be337e75230ba9341e1e67a03f84f6b1 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 17:18:05 -0700 Subject: [PATCH 050/189] Include the admonition term at the start of the admonition This adds the term ("Warning") at the beginning of the admonition with a standardized styling (bold italics, with a colon). This ensures uniform styling. --- mdbook-spec/src/lib.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 0c3cb4d..01924ac 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -131,15 +131,28 @@ impl Spec { ADMONITION_RE .replace_all(&chapter.content, |caps: &Captures<'_>| { let lower = caps["admon"].to_lowercase(); + let term = to_initial_case(&caps["admon"]); + let blockquote = &caps["blockquote"]; format!( - "
    \n\n{}\n\n
    \n", - &caps["blockquote"] + "
    \n\ + \n\ + > ***{term}:***\n\ + {blockquote}\n\ + \n\ +
    \n", ) }) .to_string() } } +fn to_initial_case(s: &str) -> String { + let mut chars = s.chars(); + let first = chars.next().expect("not empty").to_uppercase(); + let rest = chars.as_str().to_lowercase(); + format!("{first}{rest}") +} + impl Preprocessor for Spec { fn name(&self) -> &str { "spec" From e05801c1d958a931e86e1e23466426c228263193 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 17:19:23 -0700 Subject: [PATCH 051/189] Fix indented admonitions This fixes the formatting for admonitions when they are indented. The code was missing the indentation for the parts that it was adding, which made it overall inconsistent and fail to render correctly. --- mdbook-spec/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 01924ac..cef370a 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -133,13 +133,15 @@ impl Spec { let lower = caps["admon"].to_lowercase(); let term = to_initial_case(&caps["admon"]); let blockquote = &caps["blockquote"]; + let initial_spaces = blockquote.chars().position(|ch| ch != ' ').unwrap_or(0); + let space = &blockquote[..initial_spaces]; format!( - "
    \n\ + "{space}
    \n\ \n\ - > ***{term}:***\n\ + {space}> ***{term}:***\n\ {blockquote}\n\ \n\ -
    \n", + {space}
    \n", ) }) .to_string() From 838bdb570990ae0f7dc001e905d0918ac5cb1841 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 29 Aug 2024 08:04:33 -0700 Subject: [PATCH 052/189] De-wrap warning blocks --- src/behavior-considered-undefined.md | 8 +------- src/items/external-blocks.md | 5 +---- src/names/preludes.md | 4 +--- src/patterns.md | 4 +--- src/type-layout.md | 12 ++---------- 5 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index a03951d..757d0cd 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -14,13 +14,7 @@ undefined behavior, it is *unsound*.
    -***Warning:*** The following list is not exhaustive; it may grow or shrink. -There is no formal model of Rust's semantics for what is and is not allowed in -unsafe code, so there may be more behavior considered unsafe. We also reserve -the right to make some of the behavior in that list defined in the future. In -other words, this list does not say that anything will *definitely* always be -undefined in all future Rust version (but we might make such commitments for -some list items in the future). +***Warning:*** The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust's semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. We also reserve the right to make some of the behavior in that list defined in the future. In other words, this list does not say that anything will *definitely* always be undefined in all future Rust version (but we might make such commitments for some list items in the future). Please read the [Rustonomicon] before writing unsafe code. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index bb59af8..6223e32 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -294,10 +294,7 @@ that symbol rather than having to look it up by name.
    -Warning: `link_ordinal` should only be used in cases where the ordinal of the -symbol is known to be stable: if the ordinal of a symbol is not explicitly set -when its containing binary is built then one will be automatically assigned to -it, and that assigned ordinal may change between builds of the binary. +Warning: `link_ordinal` should only be used in cases where the ordinal of the symbol is known to be stable: if the ordinal of a symbol is not explicitly set when its containing binary is built then one will be automatically assigned to it, and that assigned ordinal may change between builds of the binary.
    diff --git a/src/names/preludes.md b/src/names/preludes.md index 7e6b7d4..1e1756b 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -93,9 +93,7 @@ The *`no_std` [attribute]* may be applied at the crate level to prevent the
    -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. +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.
    diff --git a/src/patterns.md b/src/patterns.md index 479bb62..585b398 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -144,9 +144,7 @@ Since negative numbers are not [literals], literal patterns also accept an optio
    -C string and raw C string literals are accepted in literal patterns, but `&CStr` -doesn't implement structural equality (`#[derive(Eq, PartialEq)]`) and therefore -any such `match` on a `&CStr` will be rejected with a type error. +C string and raw C string literals are accepted in literal patterns, but `&CStr` doesn't implement structural equality (`#[derive(Eq, PartialEq)]`) and therefore any such `match` on a `&CStr` will be rejected with a type error.
    diff --git a/src/type-layout.md b/src/type-layout.md index f558b5a..0af79de 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -256,9 +256,7 @@ struct.size = current_offset + padding_needed_for(current_offset, struct.alignme
    -Warning: This pseudocode uses a naive algorithm that ignores overflow issues for -the sake of clarity. To perform memory layout computations in actual code, use -[`Layout`]. +Warning: This pseudocode uses a naive algorithm that ignores overflow issues for the sake of clarity. To perform memory layout computations in actual code, use [`Layout`].
    @@ -310,13 +308,7 @@ the default `enum` size and alignment for the target platform's C ABI.
    -Warning: There are crucial differences between an `enum` in the C language and -Rust's [field-less enums] with this representation. An `enum` in C is -mostly a `typedef` plus some named constants; in other words, an object of an -`enum` type can hold any integer value. For example, this is often used for -bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold -the discriminant values, everything else is [undefined behavior]. Therefore, -using a field-less enum in FFI to model a C `enum` is often wrong. +Warning: There are crucial differences between an `enum` in the C language and Rust's [field-less enums] with this representation. An `enum` in C is mostly a `typedef` plus some named constants; in other words, an object of an `enum` type can hold any integer value. For example, this is often used for bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold the discriminant values, everything else is [undefined behavior]. Therefore, using a field-less enum in FFI to model a C `enum` is often wrong.
    From 0018a1ca86b3fbe944a8de38066d86291c6625e9 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 17:36:31 -0700 Subject: [PATCH 053/189] Switch warnings from div to blockquote admonitions This switches the custom div-based warnings to the admonition syntax provided by the mdbook-spec extension. --- src/behavior-considered-undefined.md | 11 ++++------- src/conditional-compilation.md | 7 ++----- src/expressions/method-call-expr.md | 13 +++++-------- src/expressions/operator-expr.md | 25 +++++++++---------------- src/introduction.md | 17 +++++------------ src/items/external-blocks.md | 7 ++----- src/names/preludes.md | 7 ++----- src/patterns.md | 7 ++----- src/type-layout.md | 14 ++++---------- 9 files changed, 35 insertions(+), 73 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 757d0cd..e60fe47 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -12,13 +12,10 @@ behaviors. `unsafe` code that satisfies this property for any safe client is called *sound*; if `unsafe` code can be misused by safe code to exhibit undefined behavior, it is *unsound*. -
    - -***Warning:*** The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust's semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. We also reserve the right to make some of the behavior in that list defined in the future. In other words, this list does not say that anything will *definitely* always be undefined in all future Rust version (but we might make such commitments for some list items in the future). - -Please read the [Rustonomicon] before writing unsafe code. - -
    +> [!WARNING] +> The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust's semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. We also reserve the right to make some of the behavior in that list defined in the future. In other words, this list does not say that anything will *definitely* always be undefined in all future Rust version (but we might make such commitments for some list items in the future). +> +> Please read the [Rustonomicon] before writing unsafe code. * Data races. * Accessing (loading from or storing to) a place that is [dangling] or [based on diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index e445475..f73f835 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -55,11 +55,8 @@ configuration option from within the source code of the crate being compiled. > by [Cargo][cargo-feature] for specifying compile-time options and optional > dependencies. -
    - -Warning: Arbitrarily-set configuration options can clash with compiler-set configuration options. For example, it is possible to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and have both `unix` and `windows` configuration options set at the same time. Doing this would be unwise. - -
    +> [!WARNING] +> Arbitrarily-set configuration options can clash with compiler-set configuration options. For example, it is possible to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and have both `unix` and `windows` configuration options set at the same time. Doing this would be unwise. ### `target_arch` diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index ca7f185..9535cd2 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -73,14 +73,11 @@ These cases require a [disambiguating function call syntax] for method and funct > This special case may be removed in the future. -
    - -***Warning:*** For [trait objects], if there is an inherent method of the same name as a trait method, it will give a compiler error when trying to call the method in a method call expression. -Instead, you can call the method using [disambiguating function call syntax], in which case it calls the trait method, not the inherent method. -There is no way to call the inherent method. -Just don't define inherent methods on trait objects with the same name as a trait method and you'll be fine. - -
    +> [!WARNING] +> For [trait objects], if there is an inherent method of the same name as a trait method, it will give a compiler error when trying to call the method in a method call expression. +> Instead, you can call the method using [disambiguating function call syntax], in which case it calls the trait method, not the inherent method. +> There is no way to call the inherent method. +> Just don't define inherent methods on trait objects with the same name as a trait method and you'll be fine. [_CallParams_]: call-expr.md [_Expression_]: ../expressions.md diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index ea39841..a9e91f0 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -455,14 +455,10 @@ If the integer type is smaller than the pointer type, the address may be truncat Casting from an integer to a raw pointer interprets the integer as a memory address and produces a pointer referencing that memory. -
    - -Warning: -This interacts with the Rust memory model, which is still under development. -A pointer obtained from this cast may suffer additional restrictions even if it is bitwise equal to a valid pointer. -Dereferencing such a pointer may be [undefined behavior] if aliasing rules are not followed. - -
    +> [!WARNING] +> This interacts with the Rust memory model, which is still under development. +> A pointer obtained from this cast may suffer additional restrictions even if it is bitwise equal to a valid pointer. +> Dereferencing such a pointer may be [undefined behavior] if aliasing rules are not followed. A trivial example of sound address arithmetic: @@ -642,14 +638,11 @@ fn example() { Like assignment expressions, compound assignment expressions always produce [the unit value][unit]. -
    - -Warning: The evaluation order of operands swaps depending on the types of the operands: -with primitive types the right-hand side will get evaluated first, while with non-primitive types the left-hand side will get evaluated first. -Try not to write code that depends on the evaluation order of operands in compound assignment expressions. -See [this test] for an example of using this dependency. - -
    +> [!WARNING] +> The evaluation order of operands swaps depending on the types of the operands: +> with primitive types the right-hand side will get evaluated first, while with non-primitive types the left-hand side will get evaluated first. +> Try not to write code that depends on the evaluation order of operands in compound assignment expressions. +> See [this test] for an example of using this dependency. [copies or moves]: ../expressions.md#moved-and-copied-types [dropping]: ../destructors.md diff --git a/src/introduction.md b/src/introduction.md index 2bf5beb..d19b699 100644 --- a/src/introduction.md +++ b/src/introduction.md @@ -7,13 +7,9 @@ It provides three kinds of material: - Chapters that informally describe the memory model, concurrency model, runtime services, linkage model, and debugging facilities. - Appendix chapters providing rationale and references to languages that influenced the design. -
    - -Warning: -This book is incomplete. Documenting everything takes a while. -See the [GitHub issues] for what is not documented in this book. - -
    +> [!WARNING] +> This book is incomplete. Documenting everything takes a while. +> See the [GitHub issues] for what is not documented in this book. ## Rust releases @@ -92,11 +88,8 @@ These conventions are documented here. * Warnings that show unsound behavior in the language or possibly confusing interactions of language features are in a special warning box. -
    - - Warning: This is an example warning. - -
    + > [!WARNING] + > This is an example warning. * Code snippets inline in the text are inside `` tags. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 6223e32..dbd55fb 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -292,11 +292,8 @@ to link against. An ordinal is a unique number per symbol exported by a dynamic library on Windows and can be used when the library is being loaded to find that symbol rather than having to look it up by name. -
    - -Warning: `link_ordinal` should only be used in cases where the ordinal of the symbol is known to be stable: if the ordinal of a symbol is not explicitly set when its containing binary is built then one will be automatically assigned to it, and that assigned ordinal may change between builds of the binary. - -
    +> [!WARNING] +> `link_ordinal` should only be used in cases where the ordinal of the symbol is known to be stable: if the ordinal of a symbol is not explicitly set when its containing binary is built then one will be automatically assigned to it, and that assigned ordinal may change between builds of the binary. ```rust,ignore diff --git a/src/names/preludes.md b/src/names/preludes.md index 1e1756b..6aa761c 100644 --- a/src/names/preludes.md +++ b/src/names/preludes.md @@ -91,11 +91,8 @@ The *`no_std` [attribute]* may be applied at the crate level to prevent the > 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. - -
    +> [!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. ## Language prelude diff --git a/src/patterns.md b/src/patterns.md index 585b398..305699a 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -142,11 +142,8 @@ if let (a, 3) = (1, 2) { // "(a, 3)" is refutable, and will not match _Literal patterns_ match exactly the same value as what is created by the literal. Since negative numbers are not [literals], literal patterns also accept an optional minus sign before the literal, which acts like the negation operator. -
    - -C string and raw C string literals are accepted in literal patterns, but `&CStr` doesn't implement structural equality (`#[derive(Eq, PartialEq)]`) and therefore any such `match` on a `&CStr` will be rejected with a type error. - -
    +> [!WARNING] +> C string and raw C string literals are accepted in literal patterns, but `&CStr` doesn't implement structural equality (`#[derive(Eq, PartialEq)]`) and therefore any such `match` on a `&CStr` will be rejected with a type error. Literal patterns are always refutable. diff --git a/src/type-layout.md b/src/type-layout.md index 0af79de..1f4b6b1 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -254,11 +254,8 @@ for field in struct.fields_in_declaration_order() { struct.size = current_offset + padding_needed_for(current_offset, struct.alignment); ``` -
    - -Warning: This pseudocode uses a naive algorithm that ignores overflow issues for the sake of clarity. To perform memory layout computations in actual code, use [`Layout`]. - -
    +> [!WARNING] +> This pseudocode uses a naive algorithm that ignores overflow issues for the sake of clarity. To perform memory layout computations in actual code, use [`Layout`]. > Note: This algorithm can produce zero-sized structs. In C, an empty struct > declaration like `struct Foo { }` is illegal. However, both gcc and clang @@ -306,11 +303,8 @@ the default `enum` size and alignment for the target platform's C ABI. > really a "best guess". In particular, this may be incorrect when the C code > of interest is compiled with certain flags. -
    - -Warning: There are crucial differences between an `enum` in the C language and Rust's [field-less enums] with this representation. An `enum` in C is mostly a `typedef` plus some named constants; in other words, an object of an `enum` type can hold any integer value. For example, this is often used for bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold the discriminant values, everything else is [undefined behavior]. Therefore, using a field-less enum in FFI to model a C `enum` is often wrong. - -
    +> [!WARNING] +> There are crucial differences between an `enum` in the C language and Rust's [field-less enums] with this representation. An `enum` in C is mostly a `typedef` plus some named constants; in other words, an object of an `enum` type can hold any integer value. For example, this is often used for bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold the discriminant values, everything else is [undefined behavior]. Therefore, using a field-less enum in FFI to model a C `enum` is often wrong. #### `#[repr(C)]` Enums With Fields From 712cd5000de2c41431dfe32344598eeca18224e2 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 17:36:54 -0700 Subject: [PATCH 054/189] Update comment now that warnings use admonitions --- theme/reference.css | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/theme/reference.css b/theme/reference.css index 04b6215..5042abd 100644 --- a/theme/reference.css +++ b/theme/reference.css @@ -11,15 +11,11 @@ the parenthetical. So for this example, you'd use } /* -Warnings and notes: +Warnings are defined using admonitions in blockquotes: -Write the
    s on their own line. E.g. +> [!WARNING] +> This is bad! -
    - -Warning: This is bad! - -
    */ main .warning p { padding: 10px 20px; From b6ab3078d2624f084b649123723531028ade577c Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 28 Aug 2024 17:38:37 -0700 Subject: [PATCH 055/189] Fix CSS styling for warning admonitions Now that warnings are wrapped in blockquotes, the CSS needs to be adjusted for that. This also includes a minor fix for the `::before` rule so that it only applies to the first paragraph in a multi-paragraph warning. --- theme/reference.css | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/theme/reference.css b/theme/reference.css index 5042abd..cbc7aca 100644 --- a/theme/reference.css +++ b/theme/reference.css @@ -17,36 +17,40 @@ Warnings are defined using admonitions in blockquotes: > This is bad! */ -main .warning p { - padding: 10px 20px; - margin: 20px 0; +main .warning blockquote { + padding: 0px; } -main .warning p::before { +main .warning blockquote p { + padding: 0px 20px; + margin: 10px 0; +} + +main .warning blockquote p:first-child::before { content: "⚠️ "; } -.light main .warning p, -.rust main .warning p { +.light main .warning blockquote, +.rust main .warning blockquote { border: 2px solid red; background: #ffcece; } -.rust main .warning p { +.rust main .warning blockquote { /* overrides previous declaration */ border-color: #961717; } -.coal main .warning p, -.navy main .warning p, -.ayu main .warning p { +.coal main .warning blockquote, +.navy main .warning blockquote, +.ayu main .warning blockquote { background: #542626; } /* Make the links higher contrast on dark themes */ -.coal main .warning p a, -.navy main .warning p a, -.ayu main .warning p a { +.coal main .warning blockquote p a, +.navy main .warning blockquote p a, +.ayu main .warning blockquote p a { color: #80d0d0; } From 726c011734efb6aeae76cc4f9c1ab511c5c967d9 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 29 Aug 2024 19:11:07 +0200 Subject: [PATCH 056/189] stabilize `const_extern_fn` --- src/items/functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/functions.md b/src/items/functions.md index ae698fb..820fa4b 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -217,7 +217,7 @@ Functions qualified with the `const` keyword are [const functions], as are [tuple struct] and [tuple variant] constructors. _Const functions_ can be called from within [const contexts]. -Const functions may use the [`extern`] function qualifier, but only with the `"Rust"` and `"C"` ABIs. +Const functions may use the [`extern`] function qualifier. Const functions are not allowed to be [async](#async-functions). From 63b0b5967cb8b55515dfbdaf46c5a2fb397e97a5 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 30 Aug 2024 12:53:47 +0200 Subject: [PATCH 057/189] asm!: clarify that `nomem` / `readonly` can access "private" memory --- src/inline-assembly.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 9dd02e2..3ad16a6 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -505,12 +505,12 @@ r[asm.options.supported-options.pure] The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted. r[asm.options.supported-options.nomem] -- `nomem`: The `asm!` blocks does not read or write to any memory. +- `nomem`: The `asm!` block does not read from or write to any memory accessible outside of the `asm!` block. This allows the compiler to cache the values of modified global variables in registers across the `asm!` block since it knows that they are not read or written to by the `asm!`. The compiler also assumes that this `asm!` block does not perform any kind of synchronization with other threads, e.g. via fences. r[asm.options.supported-options.readonly] -- `readonly`: The `asm!` block does not write to any memory. +- `readonly`: The `asm!` block does not write to any memory accessible outside of the `asm!` block. This allows the compiler to cache the values of unmodified global variables in registers across the `asm!` block since it knows that they are not written to by the `asm!`. The compiler also assumes that this `asm!` block does not perform any kind of synchronization with other threads, e.g. via fences. From 7ba7c2b88fc7e265538a6b34071c745a57607b0a Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 3 Sep 2024 20:21:14 +0200 Subject: [PATCH 058/189] stdcall is only a valid ABI on x86, except on windows --- src/items/functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/functions.md b/src/items/functions.md index 2a12708..8506f95 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -195,7 +195,7 @@ called from other programming languages like C: extern "C" fn new_i32() -> i32 { 0 } // Declares a function with the "stdcall" ABI -# #[cfg(target_arch = "x86_64")] +# #[cfg(any(windows, target_arch = "x86"))] extern "stdcall" fn new_i32_stdcall() -> i32 { 0 } ``` From 7392bd6afd5b93d2614ef5e2fe4b99bb4fb43f24 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 7 Sep 2024 21:38:28 +0100 Subject: [PATCH 059/189] Document limitations on block doc comments --- src/comments.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/comments.md b/src/comments.md index 795bf63..9b4262a 100644 --- a/src/comments.md +++ b/src/comments.md @@ -45,7 +45,8 @@ Line doc comments beginning with exactly _three_ slashes (`///`), and block doc comments (`/** ... */`), both outer doc comments, are interpreted as a special syntax for [`doc` attributes]. That is, they are equivalent to writing `#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into -`#[doc="Foo"]` and `/** Bar */` turns into `#[doc="Bar"]`. +`#[doc="Foo"]` and `/** Bar */` turns into `#[doc="Bar"]`. They must therefore +appear before something that accepts an outer attribute. Line comments beginning with `//!` and block comments `/*! ... */` are doc comments that apply to the parent of the comment, rather than the item @@ -55,6 +56,12 @@ modules that occupy a source file. The character `U+000D` (CR) is not allowed in doc comments. +It is conventional for doc comments to contain Markdown, as expected by +`rustdoc`. However, the comment syntax does not respect any internal Markdown. +``/** `glob = "*/*.rs";` */`` terminates the comment at the first `*/`, and the +remaining code would cause a syntax error. This slightly limits the content of +block doc comments compared to line doc comments. + > **Note**: The sequence `U+000D` (CR) immediately followed by `U+000A` (LF) would have been previously transformed into a single `U+000A` (LF). ## Examples From 7599e6db8023624bf88a9e63de1e1ae097021645 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 9 Sep 2024 17:36:26 +0200 Subject: [PATCH 060/189] also mention 'static's as a possible base for place projections --- src/behavior-considered-undefined.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index e60fe47..63fa28f 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -78,7 +78,7 @@ The span of bytes a pointer or reference "points to" is determined by the pointe A place is said to be "based on a misaligned pointer" if the last `*` projection during place computation was performed on a pointer that was not aligned for its type. (If there is no `*` projection in the place expression, then this is -accessing the field of a local and rustc will guarantee proper alignment. If +accessing the field of a local or `static` and rustc will guarantee proper alignment. If there are multiple `*` projection, then each of them incurs a load of the pointer-to-be-dereferenced itself from memory, and each of these loads is subject to the alignment constraint. Note that some `*` projections can be From 33ca0cddb7a1138975f0dc5d3bf116686c620259 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 9 Sep 2024 23:30:02 +0200 Subject: [PATCH 061/189] Update type_system.md --- src/attributes/type_system.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index dd3ea98..2cbe7d0 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -163,11 +163,32 @@ match message { } ``` -It's also not allowed to cast non-exhaustive types from foreign crates. +In Rust, casting non-exhaustive types from foreign crates is generally disallowed, except when dealing with enums that have no non-exhaustive variants. + +For example, the following enum can be cast because it doesn't contain any non-exhaustive variants: +```rust, ignore +#[non_exhaustive] +pub enum Example { + First, + Second +} +``` + +However, if the enum contains even a single non-exhaustive variant, casting will result in an error. Consider this modified version of the same enum: + +```rust, ignore +#[non_exhaustive] +pub enum Example { + First, + #[non_exhaustive] + Second +} +``` + ```rust, ignore -use othercrate::NonExhaustiveEnum; +use othercrate::NonExhaustiveEnumVariants; -// Cannot cast a non-exhaustive enum outside of its defining crate. +// cannot cast an enum with a non-exhaustive variant when it's defined in another crate let _ = NonExhaustiveEnum::default() as u8; ``` From fb4fb1f670c67ae77d9f9d3a8bcc7564125e1d02 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 9 Sep 2024 23:32:25 +0200 Subject: [PATCH 062/189] Update type_system.md with proper Enum name --- src/attributes/type_system.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index 2cbe7d0..c1c0c78 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -163,7 +163,7 @@ match message { } ``` -In Rust, casting non-exhaustive types from foreign crates is generally disallowed, except when dealing with enums that have no non-exhaustive variants. +However, casting non-exhaustive types from foreign crates is generally disallowed, except when dealing with enums that have no non-exhaustive variants. For example, the following enum can be cast because it doesn't contain any non-exhaustive variants: ```rust, ignore @@ -186,10 +186,10 @@ pub enum Example { ``` ```rust, ignore -use othercrate::NonExhaustiveEnumVariants; +use othercrate::EnumWithNonExhaustiveEnumVariants; -// cannot cast an enum with a non-exhaustive variant when it's defined in another crate -let _ = NonExhaustiveEnum::default() as u8; +// Error: cannot cast an enum with a non-exhaustive variant when it's defined in another crate +let _ = EnumWithNonExhaustiveEnumVariants::default() as u8; ``` Non-exhaustive types are always considered inhabited in downstream crates. From 8fc749bffd6dfab46adb1062327ec53aa52fa67b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 9 Sep 2024 23:47:47 +0200 Subject: [PATCH 063/189] Reword first sentence to be more specific. Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> --- src/attributes/type_system.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index c1c0c78..f8691b3 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -163,7 +163,7 @@ match message { } ``` -However, casting non-exhaustive types from foreign crates is generally disallowed, except when dealing with enums that have no non-exhaustive variants. +It's also not allowed to use numeric casts (`as`) on enums that contain any non-exhaustive variants. For example, the following enum can be cast because it doesn't contain any non-exhaustive variants: ```rust, ignore From 44ad71eccb42475e7f1ecc20784ca0af889d8c28 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 10 Sep 2024 12:49:29 +0200 Subject: [PATCH 064/189] type-layout: mention that call ABI compatibility is a separate concern --- src/type-layout.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/type-layout.md b/src/type-layout.md index 1f4b6b1..2edab79 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -7,6 +7,10 @@ of type layout. Type layout can be changed with each compilation. Instead of trying to document exactly what is done, we only document what is guaranteed today. +Note that even types with the same layout can still differ in how they are passed +across function boundaries. For function call ABI compatibility of types, +see [here][fn-abi-compatibility]. + ## Size and Alignment All values have an alignment and size. @@ -593,6 +597,7 @@ used with any other representation. [`Copy`]: std::marker::Copy [dynamically sized types]: dynamically-sized-types.md [field-less enums]: items/enumerations.md#field-less-enum +[fn-abi-compatibility]: ../core/primitive.fn.md#abi-compatibility [enumerations]: items/enumerations.md [zero-variant enums]: items/enumerations.md#zero-variant-enums [undefined behavior]: behavior-considered-undefined.md From cf66339fccce6a986a4d5129c5a53f59c3cebaa2 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 10 Sep 2024 14:25:42 -0400 Subject: [PATCH 065/189] Explain how to name rule identifiers --- docs/authoring.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/authoring.md b/docs/authoring.md index 74c9bc9..5fbbbe9 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -75,6 +75,36 @@ Rules can be linked to by their ID using markdown such as `[foo.bar]`. There are In the HTML, the rules are clickable just like headers. +When assigning rules to new paragraphs, or when modifying rule names, use the following guidelines: +1. A rule applies to one core idea, which should be easily determined when reading the paragraph it is applied to, +2. Other than the "intro" paragraph, purely explanatory, expository, or exemplary content does not need a rule. If the expository paragraph isn't directly related to the previous, separate it with a hard (rendered) line break +3. Rust Code examples and tests do not need their own rules +4. Notes do not need rules. For other admonition types, use the following guidelines: + * Warning: Omit the rule if and only if the warning follows from the previous paragraph. + * Target Specific Behaviour: Always include the rule + * Edition Differences: Always include the rule + * Version History: Omit the rule if the present behaviour is explained in the immediately preceeding rule. +4. The following keywords should be used to identify paragraphs when unambiguous: + * `intro`: The beginning paragraph of each section - should explain the construct being defined overall. + * `syntax`: Syntax definitions or explanations when BNF syntax definitions are not used + * `restriction`: Syntactic (parsing) requirements on the construct + * `constraint`: Semantic (type checking) requirements on the construct + * `safety` (instead of restriction): Stating that an operation is `unsafe` or the conditions under which it is `unsafe` + * `behavior`: Runtime effects of evaluating the construct in a well-defined manner + * `panics`: Conditions under which evaluating the construct causes a runtime panic + * `preconditions`: Conditions which must be satisfied for the evaluation of the construct to be well-defined + * `namespace`: For items only, specifies the namespace(s) the item introduces a name in. May also be used elsewhere when defining a namespace (e.g. `r[attribute.diagnostic.namespace]`) +5. When a rule doesn't fall under the above keywords. or for section rule ids, name the subrule as follows: + * If the rule is naming a specific Rust language construct (IE. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s) + * Other than rust language concepts with `_`s in the name, use `-` characters to separate words within a "subrule" + * Whenever possible, do not repeat previous components of the rule + * Prefer using singular forms of words over plural unless the rule applies to a list or the construct is named as plural in the language (e.g. `r[attribute.diagnostic.lint.group]) + * Whenever possible, don't use a name that conflicts with one of the above keywords, even if this violates the first bullet. + * Use an appropriately discriptive, but short, name if the language does not provide one. +6. When a keyword applies, but multiple different rules in the same section would use the same keyword, prefix or suffix the rule with a descriptive id given above, separated with a `-` + * When the paragraph modifies a specific named construct or applies to a specific named construct only, prefix the rule with the name of the construct (e.g. `r[items.fn.params.self-constraint]`). + * When the paragraph refers to a specific named construct that applies the particular keyword behaviour, suffix the rule with the name of the construct + ### Standard library links You should link to the standard library without specifying a URL in a fashion similar to [rustdoc intra-doc links][intra]. Some examples: From 078939f3b873f6af5a55781402bbac1d088646b0 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 10 Sep 2024 12:19:27 -0700 Subject: [PATCH 066/189] Fixup exhaustive enum examples Examples don't need to be ignored when they compile correctly. Use the same enum name between the definition and the use. I think this helps tie to the two examples together. Don't use `default()` when default isn't derived in the example. --- src/attributes/type_system.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index f8691b3..d3ea632 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -166,7 +166,8 @@ match message { It's also not allowed to use numeric casts (`as`) on enums that contain any non-exhaustive variants. For example, the following enum can be cast because it doesn't contain any non-exhaustive variants: -```rust, ignore + +```rust #[non_exhaustive] pub enum Example { First, @@ -176,20 +177,21 @@ pub enum Example { However, if the enum contains even a single non-exhaustive variant, casting will result in an error. Consider this modified version of the same enum: -```rust, ignore +```rust #[non_exhaustive] -pub enum Example { +pub enum EnumWithNonExhaustiveVariants { First, #[non_exhaustive] Second } ``` -```rust, ignore -use othercrate::EnumWithNonExhaustiveEnumVariants; + +```rust,ignore +use othercrate::EnumWithNonExhaustiveVariants; // Error: cannot cast an enum with a non-exhaustive variant when it's defined in another crate -let _ = EnumWithNonExhaustiveEnumVariants::default() as u8; +let _ = EnumWithNonExhaustiveVariants::First as u8; ``` Non-exhaustive types are always considered inhabited in downstream crates. From 9dfbb0c69bc3a1bdc9b2375350f0e4cb09a9ba35 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 12 Sep 2024 10:47:01 -0400 Subject: [PATCH 067/189] Add identifier syntax to statements.md --- src/statements-and-expressions.md | 2 ++ src/statements.md | 36 ++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/statements-and-expressions.md b/src/statements-and-expressions.md index fede411..b749696 100644 --- a/src/statements-and-expressions.md +++ b/src/statements-and-expressions.md @@ -1,5 +1,7 @@ # Statements and expressions +r[stmt-expr] + Rust is _primarily_ an expression language. This means that most forms of value-producing or effect-causing evaluation are directed by the uniform syntax category of _expressions_. Each kind of expression can typically _nest_ within each other kind of expression, and rules for evaluation of expressions involve specifying both the value produced by the expression and the order in which its sub-expressions are themselves evaluated. diff --git a/src/statements.md b/src/statements.md index 40f95be..5ee35d9 100644 --- a/src/statements.md +++ b/src/statements.md @@ -1,5 +1,8 @@ # Statements +r[statement] + +r[statement.syntax] > **Syntax**\ > _Statement_ :\ >       `;`\ @@ -8,13 +11,16 @@ >    | [_ExpressionStatement_]\ >    | [_MacroInvocationSemi_] - +r[statement.intro] A *statement* is a component of a [block], which is in turn a component of an outer [expression] or [function]. +r[statement.kind] Rust has two kinds of statement: [declaration statements](#declaration-statements) and [expression statements](#expression-statements). ## Declaration statements +r[statement.decl] + A *declaration statement* is one that introduces one or more *names* into the enclosing statement block. The declared names may denote new variables or new [items][item]. @@ -22,12 +28,20 @@ The two kinds of declaration statements are item declarations and `let` statemen ### Item declarations +r[statement.item] + +r[statement.item.intro] An *item declaration statement* has a syntactic form identical to an [item declaration][item] within a [module]. + +r[statement.item.scope] Declaring an item within a statement block restricts its [scope] to the block containing the statement. The item is not given a [canonical path] nor are any sub-items it may declare. + +r[statement.item.associated-scope] The exception to this is that associated items defined by [implementations] are still accessible in outer scopes as long as the item and, if applicable, trait are accessible. It is otherwise identical in meaning to declaring the item inside a module. +r[statement.item.outer-generics] There is no implicit capture of the containing function's generic parameters, parameters, and local variables. For example, `inner` may not access `outer_var`. @@ -43,6 +57,9 @@ fn outer() { ### `let` statements +r[statement.let] + +r[statement.let.syntax] > **Syntax**\ > _LetStatement_ :\ >    [_OuterAttribute_]\* `let` [_PatternNoTopAlt_] @@ -52,13 +69,21 @@ fn outer() { > † When an `else` block is specified, the > _Expression_ must not be a [_LazyBooleanExpression_], or end with a `}`. +r[statement.let.intro] A *`let` statement* introduces a new set of [variables], given by a [pattern]. The pattern is followed optionally by a type annotation and then either ends, or is followed by an initializer expression plus an optional `else` block. + +r[statement.let.inference] When no type annotation is given, the compiler will infer the type, or signal an error if insufficient type information is available for definite inference. + +r[statement.let.scope] Any variables introduced by a variable declaration are visible from the point of declaration until the end of the enclosing block scope, except when they are shadowed by another variable declaration. +r[statement.let.constraint] If an `else` block is not present, the pattern must be irrefutable. If an `else` block is present, the pattern may be refutable. + +r[statement.let.behavior] If the pattern does not match (this requires it to be refutable), the `else` block is executed. The `else` block must always diverge (evaluate to the [never type]). @@ -75,17 +100,24 @@ let [u, v] = [v[0], v[1]] else { // This pattern is irrefutable, so the compiler ## Expression statements +r[statement.expr] + +r[statement.expr.syntax] > **Syntax**\ > _ExpressionStatement_ :\ >       [_ExpressionWithoutBlock_][expression] `;`\ >    | [_ExpressionWithBlock_][expression] `;`? +r[statement.expr.intro] An *expression statement* is one that evaluates an [expression] and ignores its result. As a rule, an expression statement's purpose is to trigger the effects of evaluating its expression. +r[statement.expr.restriction-semicolon] An expression that consists of only a [block expression][block] or control flow expression, if used in a context where a statement is permitted, can omit the trailing semicolon. This can cause an ambiguity between it being parsed as a standalone statement and as a part of another expression; in this case, it is parsed as a statement. + +r[statement.expr.constraint-block] The type of [_ExpressionWithBlock_][expression] expressions when used as statements must be the unit type. ```rust @@ -118,6 +150,8 @@ if true { ## Attributes on Statements +r[statement.attribute] + Statements accept [outer attributes]. The attributes that have meaning on a statement are [`cfg`], and [the lint check attributes]. From a975dd38eba7a3512c3ecc63efe06fd911906870 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 14 Sep 2024 09:24:41 +0800 Subject: [PATCH 068/189] Update keywords.md --- src/keywords.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keywords.md b/src/keywords.md index c6472a3..300922c 100644 --- a/src/keywords.md +++ b/src/keywords.md @@ -20,7 +20,7 @@ be used as the names of: * [Macro placeholders] * [Crates] -> **Lexer:**\ +> **Lexer:**\ > KW_AS : `as`\ > KW_BREAK : `break`\ > KW_CONST : `const`\ From 6b3c3de1723e0da62e3fb6a1ee12ccc201f199e4 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 16 Sep 2024 14:40:00 -0400 Subject: [PATCH 069/189] Add identifier syntax to subtyping.md --- src/subtyping.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/subtyping.md b/src/subtyping.md index b31e25d..38fb127 100644 --- a/src/subtyping.md +++ b/src/subtyping.md @@ -1,7 +1,13 @@ # Subtyping and Variance +r[subtype] + +r[subtype.intro] Subtyping is implicit and can occur at any stage in type checking or -inference. Subtyping is restricted to two cases: +inference. + +r[subtype.kinds] +Subtyping is restricted to two cases: variance with respect to lifetimes and between types with higher ranked lifetimes. If we were to erase lifetimes from types, then the only subtyping would be due to type equality. @@ -19,6 +25,7 @@ fn bar<'a>() { Since `'static` outlives the lifetime parameter `'a`, `&'static str` is a subtype of `&'a str`. +r[subtype.higher-ranked] [Higher-ranked] [function pointers] and [trait objects] have another subtype relation. They are subtypes of types that are given by substitutions of the higher-ranked lifetimes. Some examples: @@ -39,17 +46,26 @@ let supertype: &for<'c> fn(&'c i32, &'c i32) = subtype; ## Variance +r[subtyping.variance] + +r[subtyping.variance.intro] Variance is a property that generic types have with respect to their arguments. A generic type's *variance* in a parameter is how the subtyping of the parameter affects the subtyping of the type. +r[subtyping.variance.covariant] * `F` is *covariant* over `T` if `T` being a subtype of `U` implies that `F` is a subtype of `F` (subtyping "passes through") + +r[subtyping.variance.contravariant] * `F` is *contravariant* over `T` if `T` being a subtype of `U` implies that `F` is a subtype of `F` + +r[subtyping.variance.invariant] * `F` is *invariant* over `T` otherwise (no subtyping relation can be derived) +r[subtyping.variance.builtin-types] Variance of types is automatically determined as follows | Type | Variance in `'a` | Variance in `T` | @@ -65,6 +81,7 @@ Variance of types is automatically determined as follows | `std::marker::PhantomData` | | covariant | | `dyn Trait + 'a` | covariant | invariant | +r[subtyping.variance.user-composite-types] The variance of other `struct`, `enum`, and `union` types is decided by looking at the variance of the types of their fields. If the parameter is used in positions with different variances then the parameter is invariant. For @@ -85,6 +102,7 @@ struct Variance<'a, 'b, 'c, T, U: 'a> { } ``` +r[subtyping.variance.builtin-composite-types] When used outside of an `struct`, `enum`, or `union`, the variance for parameters is checked at each location separately. ```rust From f702e597dcdb550c196129f2bb5f82b28eaecf2e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 16 Sep 2024 14:59:18 -0400 Subject: [PATCH 070/189] Add identifier syntax to type-layout.md --- src/type-layout.md | 104 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 1f4b6b1..1b05342 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -1,16 +1,22 @@ # Type Layout +r[layout] + +r[layout.intro] The layout of a type is its size, alignment, and the relative offsets of its fields. For enums, how the discriminant is laid out and interpreted is also part of type layout. +r[layout.guarantees] Type layout can be changed with each compilation. Instead of trying to document exactly what is done, we only document what is guaranteed today. ## Size and Alignment +r[layout.properties] All values have an alignment and size. +r[layout.properties.align] The *alignment* of a value specifies what addresses are valid to store the value at. A value of alignment `n` must only be stored at an address that is a multiple of n. For example, a value with an alignment of 2 must be stored at an @@ -18,6 +24,7 @@ even address, while a value with an alignment of 1 can be stored at any address. Alignment is measured in bytes, and must be at least 1, and always a power of 2. The alignment of a value can be checked with the [`align_of_val`] function. +r[layout.properties.size] The *size* of a value is the offset in bytes between successive elements in an array with that item type including alignment padding. The size of a value is always a multiple of its alignment. Note that some types are zero-sized; 0 is @@ -25,6 +32,7 @@ considered a multiple of any alignment (for example, on some platforms, the type `[u16; 0]` has size 0 and alignment 2). The size of a value can be checked with the [`size_of_val`] function. +r[layout.properties.sized] Types where all values have the same size and alignment, and both are known at compile time, implement the [`Sized`] trait and can be checked with the [`size_of`] and [`align_of`] functions. Types that are not [`Sized`] are known @@ -34,6 +42,9 @@ the alignment of the type respectively. ## Primitive Data Layout +r[layout.primitive] + +r[layout.primitive.size] The size of most primitives is given in this table. | Type | `size_of::()`| @@ -49,10 +60,12 @@ The size of most primitives is given in this table. | `f64` | 8 | | `char` | 4 | +r[layout.primitive.size-int] `usize` and `isize` have a size big enough to contain every address on the target platform. For example, on a 32 bit target, this is 4 bytes, and on a 64 bit target, this is 8 bytes. +r[layout.primitive.align] The alignment of primitives is platform-specific. In most cases, their alignment is equal to their size, but it may be less. In particular, `i128` and `u128` are often aligned to 4 or 8 bytes even though @@ -61,11 +74,16 @@ aligned to 4 bytes, not 8. ## Pointers and References Layout +r[layout.pointer] + +r[layout.pointer.intro] Pointers and references have the same layout. Mutability of the pointer or reference does not change the layout. +r[layout.pointer.thin] Pointers to sized types have the same size and alignment as `usize`. +r[layout.pointer.unsized] Pointers to unsized types are sized. The size and alignment is guaranteed to be at least equal to the size and alignment of a pointer. @@ -75,29 +93,42 @@ at least equal to the size and alignment of a pointer. ## Array Layout +r[layout.array] + An array of `[T; N]` has a size of `size_of::() * N` and the same alignment of `T`. Arrays are laid out so that the zero-based `nth` element of the array is offset from the start of the array by `n * size_of::()` bytes. ## Slice Layout +r[layout.slice] + Slices have the same layout as the section of the array they slice. > Note: This is about the raw `[T]` type, not pointers (`&[T]`, `Box<[T]>`, > etc.) to slices. ## `str` Layout + +r[layout.str] + String slices are a UTF-8 representation of characters that have the same layout as slices of type `[u8]`. ## Tuple Layout +r[layout.tuple] + +r[layout.tuple.general] Tuples are laid out according to the [`Rust` representation][`Rust`]. +r[layout.tuple.unit] The exception to this is the unit tuple (`()`), which is guaranteed as a zero-sized type to have a size of 0 and an alignment of 1. ## Trait Object Layout +r[layout.trait-object] + Trait objects have the same layout as the value the trait object is of. > Note: This is about the raw trait object types, not pointers (`&dyn Trait`, @@ -105,19 +136,27 @@ Trait objects have the same layout as the value the trait object is of. ## Closure Layout +r[kayout.closure] + Closures have no layout guarantees. ## Representations +r[layout.repr] + +r[layout.repr.intro] All user-defined composite types (`struct`s, `enum`s, and `union`s) have a -*representation* that specifies what the layout is for the type. The possible -representations for a type are: +*representation* that specifies what the layout is for the type. + +r[layout.repr.kinds] +The possible representations for a type are: - [`Rust`] (default) - [`C`] - The [primitive representations] - [`transparent`] +r[layout.repr.attribute] The representation of a type can be changed by applying the `repr` attribute to it. The following example shows a struct with a `C` representation. @@ -130,6 +169,7 @@ struct ThreeInts { } ``` +r[layout.repr.align-packed] The alignment may be raised or lowered with the `align` and `packed` modifiers respectively. They alter the representation specified in the attribute. If no representation is specified, the default one is altered. @@ -157,6 +197,7 @@ struct AlignedStruct { > the same name have the same representation. For example, `Foo` and > `Foo` both have the same representation. +r[layout.repr.inter-field] The representation of a type can change the padding between fields, but does not change the layout of the fields themselves. For example, a struct with a `C` representation that contains a struct `Inner` with the default @@ -164,11 +205,15 @@ representation will not change the layout of `Inner`. ### The `Rust` Representation +r[layout.repr.rust] + +r[layout.repr.rust.intro] The `Rust` representation is the default representation for nominal types without a `repr` attribute. Using this representation explicitly through a `repr` attribute is guaranteed to be the same as omitting the attribute entirely. +r[layout.repr.rust.layout] The only data layout guarantees made by this representation are those required for soundness. They are: @@ -176,8 +221,12 @@ for soundness. They are: 2. The fields do not overlap. 3. The alignment of the type is at least the maximum alignment of its fields. +r[layout.repr.rust.alignment] Formally, the first guarantee means that the offset of any field is divisible by -that field's alignment. The second guarantee means that the fields can be +that field's alignment. + +r[layout.repr.rust.field-storage] +The second guarantee means that the fields can be ordered such that the offset plus the size of any field is less than or equal to the offset of the next field in the ordering. The ordering does not have to be the same as the order in which the fields are specified in the declaration of @@ -187,10 +236,14 @@ Be aware that the second guarantee does not imply that the fields have distinct addresses: zero-sized types may have the same address as other fields in the same struct. +r[layout.repr.rust.unspecified] There are no other guarantees of data layout made by this representation. ### The `C` Representation +r[layout.repr.c] + +r[layout.repr.c.intro] The `C` representation is designed for dual purposes. One purpose is for creating types that are interoperable with the C Language. The second purpose is to create types that you can soundly perform operations on that rely on data @@ -199,13 +252,18 @@ layout such as reinterpreting values as a different type. Because of this dual purpose, it is possible to create types that are not useful for interfacing with the C programming language. +r[layout.repr.c.constraint] This representation can be applied to structs, unions, and enums. The exception is [zero-variant enums] for which the `C` representation is an error. #### `#[repr(C)]` Structs +r[layout.repr.c.struct] + +r[layour.repr.c.struct.align] The alignment of the struct is the alignment of the most-aligned field in it. +r[layout.repr.c.struct.size-field-offset] The size and offset of fields is determined by the following algorithm. Start with a current offset of 0 bytes. @@ -266,8 +324,13 @@ struct.size = current_offset + padding_needed_for(current_offset, struct.alignme #### `#[repr(C)]` Unions +r[layout.repr.c.union] + +r[layout.repr.c.union.intro] A union declared with `#[repr(C)]` will have the same size and alignment as an equivalent C union declaration in the C language for the target platform. + +r[layout.repr.c.union.size-align] The union will have a size of the maximum size of all of its fields rounded to its alignment, and an alignment of the maximum alignment of all of its fields. These maximums may come from different fields. @@ -296,6 +359,8 @@ assert_eq!(std::mem::align_of::(), 4); // From a #### `#[repr(C)]` Field-less Enums +r[layout.repr.c.enum] + For [field-less enums], the `C` representation has the size and alignment of the default `enum` size and alignment for the target platform's C ABI. @@ -308,10 +373,16 @@ the default `enum` size and alignment for the target platform's C ABI. #### `#[repr(C)]` Enums With Fields +r[layout.repr.c.adt] + +r[layout.repr.c.adt.intro] The representation of a `repr(C)` enum with fields is a `repr(C)` struct with two fields, also called a "tagged union" in C: +r[layout.repr.c.adt.tag] - a `repr(C)` version of the enum with all fields removed ("the tag") + +r[layout.repr.c.adt.fields] - a `repr(C)` union of `repr(C)` structs for the fields of each variant that had them ("the payload") @@ -374,10 +445,14 @@ struct MyDFields; ### Primitive representations +r[layout.repr.primitive] + +r[layout.repr.primitive.intro] The *primitive representations* are the representations with the same names as the primitive integer types. That is: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, and `isize`. +r[layout.repr.primitive.constraint] Primitive representations can only be applied to enumerations and have different behavior whether the enum has fields or no fields. It is an error for [zero-variant enums] to have a primitive representation. Combining @@ -385,6 +460,8 @@ two primitive representations together is an error. #### Primitive Representation of Field-less Enums +r[layout.repr.primitive.enum] + For [field-less enums], primitive representations set the size and alignment to be the same as the primitive type of the same name. For example, a field-less enum with a `u8` representation can only have discriminants between 0 and 255 @@ -392,6 +469,8 @@ inclusive. #### Primitive Representation of Enums With Fields +r[layout.repr.primitive.adt] + The representation of a primitive representation enum is a `repr(C)` union of `repr(C)` structs for each variant with a field. The first field of each struct in the union is the primitive representation version of the enum with all fields @@ -446,6 +525,8 @@ struct MyVariantD(MyEnumDiscriminant); #### Combining primitive representations of enums with fields and `#[repr(C)]` +r[layout.repr.primitive-c] + For enums with fields, it is also possible to combine `repr(C)` and a primitive representation (e.g., `repr(C, u8)`). This modifies the [`repr(C)`] by changing the representation of the discriminant enum to the chosen primitive @@ -510,6 +591,9 @@ assert_eq!(std::mem::size_of::(), 4); ### The alignment modifiers +r[layout.repr.alignment] + +r[layout.repr.alignment.intro] The `align` and `packed` modifiers can be used to respectively raise or lower the alignment of `struct`s and `union`s. `packed` may also alter the padding between fields (although it will not alter the padding inside of any field). @@ -518,28 +602,37 @@ of fields in the layout of a struct or the layout of an enum variant, although they may be combined with representations (such as `C`) which do provide such guarantees. +r[layout.repr.alignment.constraint-alignment] The alignment is specified as an integer parameter in the form of `#[repr(align(x))]` or `#[repr(packed(x))]`. The alignment value must be a power of two from 1 up to 229. For `packed`, if no value is given, as in `#[repr(packed)]`, then the value is 1. +r[layout.repr.alignment.align] For `align`, if the specified alignment is less than the alignment of the type without the `align` modifier, then the alignment is unaffected. +r[layout.repr.alignment.packed] For `packed`, if the specified alignment is greater than the type's alignment without the `packed` modifier, then the alignment and layout is unaffected. + +r[layout.repr.alignment.packed-fields] The alignments of each field, for the purpose of positioning fields, is the smaller of the specified alignment and the alignment of the field's type. + +r[layout.repr.alignment.packed-padding] Inter-field padding is guaranteed to be the minimum required in order to satisfy each field's (possibly altered) alignment (although note that, on its own, `packed` does not provide any guarantee about field ordering). An important consequence of these rules is that a type with `#[repr(packed(1))]` (or `#[repr(packed)]`) will have no inter-field padding. +r[layout.repr.alignment.constraint-exclusive] The `align` and `packed` modifiers cannot be applied on the same type and a `packed` type cannot transitively contain another `align`ed type. `align` and `packed` may only be applied to the [`Rust`] and [`C`] representations. +r[layout.repr.alignment.enum] The `align` modifier can also be applied on an `enum`. When it is, the effect on the `enum`'s alignment is the same as if the `enum` was wrapped in a newtype `struct` with the same `align` modifier. @@ -569,11 +662,15 @@ was wrapped in a newtype `struct` with the same `align` modifier. ### The `transparent` Representation +r[layout.repr.transparent] + +r[layout.repr.transparent.constraint-field] The `transparent` representation can only be used on a [`struct`][structs] or an [`enum`][enumerations] with a single variant that has: - any number of fields with size 0 and alignment 1 (e.g. [`PhantomData`]), and - at most one other field. +r[layout.repr.transparent.layout-abi] Structs and enums with this representation have the same layout and ABI as the only non-size 0 non-alignment 1 field, if present, or unit otherwise. @@ -582,6 +679,7 @@ a struct with the `C` representation will always have the ABI of a `C` `struct` while, for example, a struct with the `transparent` representation with a primitive field will have the ABI of the primitive field. +r[layout.repr.transparent.constraint-exclusive] Because this representation delegates type layout to another type, it cannot be used with any other representation. From b9f4d7342969bb828219905dd6566538f17977f0 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 17 Sep 2024 15:43:58 -0700 Subject: [PATCH 071/189] Make note about markdown a note --- src/comments.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/comments.md b/src/comments.md index 9b4262a..d395767 100644 --- a/src/comments.md +++ b/src/comments.md @@ -56,11 +56,11 @@ modules that occupy a source file. The character `U+000D` (CR) is not allowed in doc comments. -It is conventional for doc comments to contain Markdown, as expected by -`rustdoc`. However, the comment syntax does not respect any internal Markdown. -``/** `glob = "*/*.rs";` */`` terminates the comment at the first `*/`, and the -remaining code would cause a syntax error. This slightly limits the content of -block doc comments compared to line doc comments. +> **Note**: It is conventional for doc comments to contain Markdown, as expected by +> `rustdoc`. However, the comment syntax does not respect any internal Markdown. +> ``/** `glob = "*/*.rs";` */`` terminates the comment at the first `*/`, and the +> remaining code would cause a syntax error. This slightly limits the content of +> block doc comments compared to line doc comments. > **Note**: The sequence `U+000D` (CR) immediately followed by `U+000A` (LF) would have been previously transformed into a single `U+000A` (LF). From 9892c817045518604d9b2032062921ffd22c36c5 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 17 Sep 2024 15:51:02 -0700 Subject: [PATCH 072/189] Switch to normalization Use the same word as used in the section title. --- src/identifiers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/identifiers.md b/src/identifiers.md index 66b9d1a..1013a58 100644 --- a/src/identifiers.md +++ b/src/identifiers.md @@ -62,7 +62,7 @@ r[ident.ascii-extern-item] ## Normalization -r[ident.normalize] +r[ident.normalization] Identifiers are normalized using Normalization Form C (NFC) as defined in [Unicode Standard Annex #15][UAX15]. Two identifiers are equal if their NFC forms are equal. From 5fa10870399b1ba070e6dd38c02cb628c139f87e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 17 Sep 2024 15:52:37 -0700 Subject: [PATCH 073/189] Remove ascii-limitations specific rules This particular section didn't feel like it needed separate rule identifiers for each list item. I think anything needing to refer to the restrictions around ascii can just link to `ident.ascii-limitations`, and the user should be able to see what it is referring to. --- src/identifiers.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/identifiers.md b/src/identifiers.md index 1013a58..f34ae48 100644 --- a/src/identifiers.md +++ b/src/identifiers.md @@ -45,19 +45,10 @@ Zero width non-joiner (ZWNJ U+200C) and zero width joiner (ZWJ U+200D) character r[ident.ascii-limitations] Identifiers are restricted to the ASCII subset of [`XID_Start`] and [`XID_Continue`] in the following situations: -r[ident.ascii-extern-crate] * [`extern crate`] declarations - -r[ident.ascii-extern-prelude] * External crate names referenced in a [path] - -r[ident.ascii-outlined-module] * [Module] names loaded from the filesystem without a [`path` attribute] - -r[ident.ascii-no_mangle] * [`no_mangle`] attributed items - -r[ident.ascii-extern-item] * Item names in [external blocks] ## Normalization From 2a1796827f14b6c30d8e631ea7342e5121876438 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 21:37:37 -0400 Subject: [PATCH 074/189] Add spec identifier syntax to interior-mutability.md --- src/interior-mutability.md | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/interior-mutability.md b/src/interior-mutability.md index dc79aac..7f71784 100644 --- a/src/interior-mutability.md +++ b/src/interior-mutability.md @@ -1,22 +1,38 @@ # Interior Mutability +r[interior-mut] + +r[interior-mut.intro] Sometimes a type needs to be mutated while having multiple aliases. In Rust this -is achieved using a pattern called _interior mutability_. A type has interior -mutability if its internal state can be changed through a [shared reference] to -it. This goes against the usual [requirement][ub] that the value pointed to by a +is achieved using a pattern called _interior mutability_. + +r[interior-mut.shared-ref] +A type has interior mutability if its internal state can be changed through a [shared reference] to +it. + +r[interior-mut.no-constraint] +This goes against the usual [requirement][ub] that the value pointed to by a shared reference is not mutated. +r[interior-mut.unsafe-cell] [`std::cell::UnsafeCell`] type is the only allowed way to disable this requirement. When `UnsafeCell` is immutably aliased, it is still safe to -mutate, or obtain a mutable reference to, the `T` it contains. As with all -other types, it is undefined behavior to have multiple `&mut UnsafeCell` +mutate, or obtain a mutable reference to, the `T` it contains. + +r[interior-mut.mut-unsafe-cell] +As with all other types, it is undefined behavior to have multiple `&mut UnsafeCell` aliases. +r[interior-mut.abstraction] Other types with interior mutability can be created by using `UnsafeCell` as a field. The standard library provides a variety of types that provide safe -interior mutability APIs. For example, [`std::cell::RefCell`] uses run-time -borrow checks to ensure the usual rules around multiple references. The -[`std::sync::atomic`] module contains types that wrap a value that is only +interior mutability APIs. + +r[interior-mut.ref-cell] +For example, [`std::cell::RefCell`] uses run-time borrow checks to ensure the usual rules around multiple references. + +r[interior-mut.atomic] +The [`std::sync::atomic`] module contains types that wrap a value that is only accessed with atomic operations, allowing the value to be shared and mutated across threads. From 6b5e30d1619b54251bb0367f4a92c1c841564961 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 18 Sep 2024 21:41:42 -0400 Subject: [PATCH 075/189] Add identifier syntax to types and subchapters. --- src/types.md | 42 ++++++++++++++++++++++++++++++++--- src/types/array.md | 11 +++++++-- src/types/boolean.md | 40 +++++++++++++++++++++++++++++++-- src/types/closure.md | 19 ++++++++++++++++ src/types/enum.md | 7 ++++++ src/types/function-item.md | 12 ++++++++-- src/types/function-pointer.md | 14 ++++++++++-- src/types/impl-trait.md | 40 +++++++++++++++++++++++++++++++-- src/types/inferred.md | 12 ++++++++-- src/types/never.md | 11 +++++++-- src/types/numeric.md | 15 +++++++++++++ src/types/parameters.md | 2 ++ src/types/pointer.md | 35 +++++++++++++++++++++++++++++ src/types/slice.md | 6 +++++ src/types/struct.md | 8 +++++++ src/types/textual.md | 15 ++++++++++++- src/types/trait-object.md | 18 +++++++++++++-- src/types/tuple.md | 12 ++++++++++ src/types/union.md | 12 +++++++++- 19 files changed, 310 insertions(+), 21 deletions(-) diff --git a/src/types.md b/src/types.md index 0f82638..a93f93d 100644 --- a/src/types.md +++ b/src/types.md @@ -1,14 +1,21 @@ {{#include types-redirect.html}} # Types +r[type] + +r[type.intro] Every variable, item, and value in a Rust program has a type. The _type_ of a *value* defines the interpretation of the memory holding it and the operations that may be performed on the value. +r[type.builtin] Built-in types are tightly integrated into the language, in nontrivial ways -that are not possible to emulate in user-defined types. User-defined types have -limited capabilities. +that are not possible to emulate in user-defined types. + +r[type.user-defined] +User-defined types have limited capabilities. +r[type.kinds] The list of types is: * Primitive types: @@ -37,6 +44,9 @@ The list of types is: ## Type expressions +r[type.name] + +r[type.name.syntax] > **Syntax**\ > _Type_ :\ >       _TypeNoBounds_\ @@ -59,27 +69,47 @@ The list of types is: >    | [_BareFunctionType_]\ >    | [_MacroInvocation_] +r[type.name.intro] A _type expression_ as defined in the _Type_ grammar rule above is the syntax for referring to a type. It may refer to: +r[type.name.sequence] * Sequence types ([tuple], [array], [slice]). + +r[type.name.path] * [Type paths] which can reference: * Primitive types ([boolean], [numeric], [textual]). * Paths to an [item] ([struct], [enum], [union], [type alias], [trait]). * [`Self` path] where `Self` is the implementing type. * Generic [type parameters]. + +r[type.name.pointer] * Pointer types ([reference], [raw pointer], [function pointer]). + +r[type.name.inference] * The [inferred type] which asks the compiler to determine the type. + +r[type.name.grouped] * [Parentheses] which are used for disambiguation. + +r[type.name.trait] * Trait types: [Trait objects] and [impl trait]. + +r[type.name.never] * The [never] type. + +r[type.name.macro-expansion] * [Macros] which expand to a type expression. ### Parenthesized types +r[type.name.parenthesized] + +r[type.name.parenthesized.syntax] > _ParenthesizedType_ :\ >    `(` [_Type_] `)` +r[type.name.parenthesized.intro] In some situations the combination of types may be ambiguous. Use parentheses around a type to avoid ambiguity. For example, the `+` operator for [type boundaries] within a [reference type] is unclear where the @@ -94,10 +124,16 @@ type T<'a> = &'a (dyn Any + Send); ## Recursive types +r[type.recursive] + +r[type.recursive.intro] Nominal types — [structs], [enumerations], and [unions] — may be recursive. That is, each `enum` variant or `struct` or `union` field may refer, directly or indirectly, to the enclosing `enum` or `struct` type -itself. Such recursion has restrictions: +itself. + +r[type.recursive.constraint] +Such recursion has restrictions: * Recursive types must include a nominal type in the recursion (not mere [type aliases], or other structural types such as [arrays] or [tuples]). So `type diff --git a/src/types/array.md b/src/types/array.md index 167954b..a5211cb 100644 --- a/src/types/array.md +++ b/src/types/array.md @@ -1,12 +1,18 @@ # Array types +r[type.array] + +r[type.array.syntax] > **Syntax**\ > _ArrayType_ :\ >    `[` [_Type_] `;` [_Expression_] `]` +r[type.array.index] An array is a fixed-size sequence of `N` elements of type `T`. The array type -is written as `[T; N]`. The size is a [constant expression] that evaluates to a -[`usize`]. +is written as `[T; N]`. + +r[type.array.constraint] +The size is a [constant expression] that evaluates to a [`usize`]. Examples: @@ -18,6 +24,7 @@ let array: [i32; 3] = [1, 2, 3]; let boxed_array: Box<[i32]> = Box::new([1, 2, 3]); ``` +r[type.array.index] All elements of arrays are always initialized, and access to an array is always bounds-checked in safe methods and operators. diff --git a/src/types/boolean.md b/src/types/boolean.md index a0c0710..10c6e5d 100644 --- a/src/types/boolean.md +++ b/src/types/boolean.md @@ -1,31 +1,44 @@ # Boolean type +r[type.bool] + ```rust let b: bool = true; ``` +r[type.bool.intro] The *boolean type* or *bool* is a primitive data type that can take on one of two values, called *true* and *false*. +r[type.bool.literal] Values of this type may be created using a [literal expression] using the keywords `true` and `false` corresponding to the value of the same name. +r[type.bool.namespace] This type is a part of the [language prelude] with the [name] `bool`. -An object with the boolean type has a [size and alignment] of 1 each. The -value false has the bit pattern `0x00` and the value true has the bit pattern +r[type.bool.layout] +An object with the boolean type has a [size and alignment] of 1 each. + +r[type.bool.repr] +The value false has the bit pattern `0x00` and the value true has the bit pattern `0x01`. It is [undefined behavior] for an object with the boolean type to have any other bit pattern. +r[type.bool.usage] The boolean type is the type of many operands in various [expressions]: +r[type.bool.usage-condition] * The condition operand in [if expressions] and [while expressions] + +r[type.bool.usage-lazy-operator] * The operands in [lazy boolean operator expressions][lazy] > **Note**: The boolean type acts similarly to but is not an [enumerated type]. In practice, this mostly means that constructors are not associated to the type (e.g. `bool::true`). +r[type.bool.traits] Like all primitives, the boolean type [implements][p-impl] the [traits][p-traits] [`Clone`][p-clone], [`Copy`][p-copy], [`Sized`][p-sized], [`Send`][p-send], and [`Sync`][p-sync]. @@ -34,11 +47,15 @@ Like all primitives, the boolean type [implements][p-impl] the ## Operations on boolean values +r[type.bool.expr] + When using certain operator expressions with a boolean type for its operands, they evaluate using the rules of [boolean logic]. ### Logical not +r[type.bool.expr.not] + | `b` | [`!b`][op-not] | |- | - | | `true` | `false` | @@ -46,6 +63,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic]. ### Logical or +r[type.bool.expr.or] + | `a` | `b` | [a | b][op-or] | |- | - | - | | `true` | `true` | `true` | @@ -55,6 +74,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic]. ### Logical and +r[type.bool.expr.and] + | `a` | `b` | [`a & b`][op-and] | |- | - | - | | `true` | `true` | `true` | @@ -64,6 +85,8 @@ boolean type for its operands, they evaluate using the rules of [boolean logic]. ### Logical xor +r[type.bool.expr.xor] + | `a` | `b` | [`a ^ b`][op-xor] | |- | - | - | | `true` | `true` | `false` | @@ -73,6 +96,9 @@ boolean type for its operands, they evaluate using the rules of [boolean logic]. ### Comparisons +r[type.bool.expr.cmp] + +r[type.bool.expr.cmp.eq] | `a` | `b` | [`a == b`][op-compare] | |- | - | - | | `true` | `true` | `true` | @@ -80,6 +106,7 @@ boolean type for its operands, they evaluate using the rules of [boolean logic]. | `false` | `true` | `false` | | `false` | `false` | `true` | +r[type.bool.expr.cmp.greater] | `a` | `b` | [`a > b`][op-compare] | |- | - | - | | `true` | `true` | `false` | @@ -87,13 +114,22 @@ boolean type for its operands, they evaluate using the rules of [boolean logic]. | `false` | `true` | `false` | | `false` | `false` | `false` | +r[type.bool.expr.cmp.not-eq] * `a != b` is the same as `!(a == b)` + +r[type.bool.expr.cmp.greater-eq] * `a >= b` is the same as `a == b | a > b` + +r[type.bool.expr.cmp.less] * `a < b` is the same as `!(a >= b)` + +r[type.bool.expr.cmp.less-eq] * `a <= b` is the same as `a == b | a < b` ## Bit validity +r[type.bool.validity] + The single byte of a `bool` is guaranteed to be initialized (in other words, `transmute::(...)` is always sound -- but since some bit patterns are invalid `bool`s, the inverse is not always sound). diff --git a/src/types/closure.md b/src/types/closure.md index f935378..d6833ed 100644 --- a/src/types/closure.md +++ b/src/types/closure.md @@ -1,5 +1,7 @@ # Closure types +r[type.closure] + A [closure expression] produces a closure value with a unique, anonymous type that cannot be written out. A closure type is approximately equivalent to a struct which contains the captured variables. For instance, the following @@ -47,6 +49,9 @@ f(Closure{s: s, t: &t}); ## Capture modes +r[type.closure.capture] + +r[type.closure.capture.order] The compiler prefers to capture a closed-over variable by immutable borrow, followed by unique immutable borrow (see below), by mutable borrow, and finally by move. It will pick the first choice of these that is compatible with how the @@ -54,11 +59,13 @@ captured variable is used inside the closure body. The compiler does not take surrounding code into account, such as the lifetimes of involved variables, or of the closure itself. +r[type.closure.capture.move] If the `move` keyword is used, then all captures are by move or, for `Copy` types, by copy, regardless of whether a borrow would work. The `move` keyword is usually used to allow the closure to outlive the captured values, such as if the closure is being returned or used to spawn a new thread. +r[type.closure.capture.composite] Composite types such as structs, tuples, and enums are always captured entirely, not by individual fields. It may be necessary to borrow into a local variable in order to capture a single field: @@ -87,6 +94,8 @@ borrowed to iterate over, the code would not compile. ## Unique immutable borrows in captures +r[type.closure.unique-immutable] + Captures can occur by a special kind of borrow called a _unique immutable borrow_, which cannot be used anywhere else in the language and cannot be written out explicitly. It occurs when modifying the referent of a mutable @@ -115,13 +124,18 @@ the closure's lifetime has expired at the end of the block, releasing the borrow ## Call traits and coercions +r[type.closure.call] + +r[type.closure.call.intro] Closure types all implement [`FnOnce`], indicating that they can be called once by consuming ownership of the closure. Additionally, some closures implement more specific call traits: +r[type.closure.call.fn-mut] * A closure which does not move out of any captured variables implements [`FnMut`], indicating that it can be called by mutable reference. +r[type.closure.call.fn] * A closure which does not mutate or move out of any captured variables implements [`Fn`], indicating that it can be called by shared reference. @@ -130,6 +144,7 @@ more specific call traits: > closure type are determined by what the closure does with captured values, > not how it captures them. +r[type.closure.non-capturing] *Non-capturing closures* are closures that don't capture anything from their environment. They can be coerced to function pointers (e.g., `fn()`) with the matching signature. @@ -146,6 +161,9 @@ x = bo(5,7); ## Other traits +r[type.closure.traits] + +r[type.closure.traits.intro] All closure types implement [`Sized`]. Additionally, closure types implement the following traits if allowed to do so by the types of the captures it stores: @@ -154,6 +172,7 @@ following traits if allowed to do so by the types of the captures it stores: * [`Sync`] * [`Send`] +r[type.closure.traits.behavior] The rules for [`Send`] and [`Sync`] match those for normal struct types, while [`Clone`] and [`Copy`] behave as if [derived]. For [`Clone`], the order of cloning of the captured variables is left unspecified. diff --git a/src/types/enum.md b/src/types/enum.md index 1ee6fc6..a3ae287 100644 --- a/src/types/enum.md +++ b/src/types/enum.md @@ -1,17 +1,24 @@ # Enumerated types +r[type.enum] + +r[type.enum.intro] An *enumerated type* is a nominal, heterogeneous disjoint union type, denoted by the name of an [`enum` item]. [^enumtype] +r[type.enum.declaration] An [`enum` item] declares both the type and a number of *variants*, each of which is independently named and has the syntax of a struct, tuple struct or unit-like struct. +r[type.enum.constructor] New instances of an `enum` can be constructed with a [struct expression]. +r[type.enum.value] Any `enum` value consumes as much memory as the largest variant for its corresponding `enum` type, as well as the size needed to store a discriminant. +r[type.enum.name] Enum types cannot be denoted *structurally* as types, but must be denoted by named reference to an [`enum` item]. diff --git a/src/types/function-item.md b/src/types/function-item.md index 3221f3e..ef51285 100644 --- a/src/types/function-item.md +++ b/src/types/function-item.md @@ -1,13 +1,19 @@ # Function item types +r[type.fn-item] + +r[type.fn-item.intro] When referred to, a function item, or the constructor of a tuple-like struct or -enum variant, yields a zero-sized value of its _function item type_. That type -explicitly identifies the function - its name, its type arguments, and its +enum variant, yields a zero-sized value of its _function item type_. + +r[type.fn-item.unique] +That type explicitly identifies the function - its name, its type arguments, and its early-bound lifetime arguments (but not its late-bound lifetime arguments, which are only assigned when the function is called) - so the value does not need to contain an actual function pointer, and no indirection is needed when the function is called. +r[type.fn-item.name] There is no syntax that directly refers to a function item type, but the compiler will display the type as something like `fn(u32) -> i32 {fn_name}` in error messages. @@ -22,6 +28,7 @@ let x = &mut foo::; *x = foo::; //~ ERROR mismatched types ``` +r[type.fn-item.coercion] However, there is a [coercion] from function items to [function pointers] with the same signature, which is triggered not only when a function item is used when a function pointer is directly expected, but also when different function @@ -43,6 +50,7 @@ let foo_ptr_2 = if want_i32 { }; ``` +r[type.fn-item.traits] All function items implement [`Fn`], [`FnMut`], [`FnOnce`], [`Copy`], [`Clone`], [`Send`], and [`Sync`]. diff --git a/src/types/function-pointer.md b/src/types/function-pointer.md index 82103be..3fbe207 100644 --- a/src/types/function-pointer.md +++ b/src/types/function-pointer.md @@ -1,5 +1,8 @@ # Function pointer types +r[type.fn-pointer] + +r[type.fn-pointer.syntax] > **Syntax**\ > _BareFunctionType_ :\ >    [_ForLifetimes_]? _FunctionTypeQualifiers_ `fn`\ @@ -23,13 +26,18 @@ > _MaybeNamedFunctionParametersVariadic_ :\ >    ( _MaybeNamedParam_ `,` )\* _MaybeNamedParam_ `,` [_OuterAttribute_]\* `...` +r[type.fn-pointer.intro] Function pointer types, written using the `fn` keyword, refer to a function -whose identity is not necessarily known at compile-time. They can be created -via a coercion from both [function items] and non-capturing [closures]. +whose identity is not necessarily known at compile-time. + +r[type.fn-pointer.coercion] +They can be created via a coercion from both [function items] and non-capturing [closures]. +r[type.fn-pointer.qualifiers] The `unsafe` qualifier indicates that the type's value is an [unsafe function], and the `extern` qualifier indicates it is an [extern function]. +r[type.fn-pointer.constraint-variadic] Variadic parameters can only be specified with [`extern`] function types with the `"C"` or `"cdecl"` calling convention. @@ -49,6 +57,8 @@ x = bo(5,7); ## Attributes on function pointer parameters +r[type.fn-pointer.attributes] + Attributes on function pointer parameters follow the same rules and restrictions as [regular function parameters]. diff --git a/src/types/impl-trait.md b/src/types/impl-trait.md index 7e99949..a661837 100644 --- a/src/types/impl-trait.md +++ b/src/types/impl-trait.md @@ -1,10 +1,14 @@ # Impl trait +r[type.impl-trait] + +r[type.impl-trait.syntax] > **Syntax**\ > _ImplTraitType_ : `impl` [_TypeParamBounds_] > > _ImplTraitTypeOneBound_ : `impl` [_TraitBound_] +r[type.impl-trait.intro] `impl Trait` provides ways to specify unnamed but concrete types that implement a specific trait. It can appear in two sorts of places: argument position (where it can act as an anonymous type parameter to functions), and return position (where it can act as an abstract return type). @@ -23,9 +27,12 @@ fn bar() -> impl Trait { ``` ## Anonymous type parameters +r[type.impl-trait.param] + > Note: This is often called "impl Trait in argument position". (The term "parameter" is more correct here, but "impl Trait in argument position" is the phrasing used during the development of this feature, and it remains in parts of the implementation.) +r[type.impl-trait.param.intro] Functions can use `impl` followed by a set of trait bounds to declare a parameter as having an anonymous type. The caller must provide a type that satisfies the bounds declared by the anonymous type parameter, and the function can only use the methods available through the trait bounds of the anonymous type parameter. @@ -43,6 +50,7 @@ fn with_impl_trait(arg: impl Trait) { } ``` +r[type.impl-trait.param.generic] That is, `impl Trait` in argument position is syntactic sugar for a generic type parameter like ``, except that the type is anonymous and doesn't appear in the [_GenericParams_] list. > **Note:** @@ -52,10 +60,15 @@ That is, `impl Trait` in argument position is syntactic sugar for a generic type ## Abstract return types +r[type.impl-trait.return] + > Note: This is often called "impl Trait in return position". +r[type.impl-trait.return.intro] Functions can use `impl Trait` to return an abstract return type. These types stand in for another concrete type where the caller may only use the methods declared by the specified `Trait`. + +r[type.impl-trait.return.constraint-body] Each possible return value from the function must resolve to the same concrete type. `impl Trait` in return position allows a function to return an unboxed abstract type. @@ -87,22 +100,38 @@ Returning `impl Iterator` means that a function only exposes the `Iterator` trai ## Return-position `impl Trait` in traits and trait implementations +r[type.impl-trait.return-in-trait] + +r[type.impl-trait.return-in-trait.intro] Functions in traits may also use `impl Trait` as a syntax for an anonymous associated type. +r[type.impl-trait.return-in-trait.desugaring] Every `impl Trait` in the return type of an associated function in a trait is desugared to an anonymous associated type. The return type that appears in the implementation's function signature is used to determine the value of the associated type. ## Capturing +r[type.impl-trait.generic-captures] + Behind each return-position `impl Trait` abstract type is some hidden concrete type. For this concrete type to use a generic parameter, that generic parameter must be *captured* by the abstract type. ## Automatic capturing +r[type.impl-trait.generic-capture.auto] + +r[type.impl-trait.generic-capture.auto.intro] Return-position `impl Trait` abstract types automatically capture certain of the in-scope generic parameters. Everywhere, these automatically capture all in-scope type and const generic parameters. -On items of trait impls and trait definitions, these types additionally automatically capture all in-scope generic lifetime parameters, including higher-ranked ones. On free functions and on associated functions and methods of inherent impls, only the generic lifetime parameters that appear in the bounds of abstract return type are captured. +r[type.impl-trait.generic-capture.auto.trait] +On items of trait impls and trait definitions, these types additionally automatically capture all in-scope generic lifetime parameters, including higher-ranked ones. + +r[type.impl-trait.generic-capture.auto.fn] +On free functions and on associated functions and methods of inherent impls, only the generic lifetime parameters that appear in the bounds of abstract return type are captured. ## Precise capturing +r[type.impl-trait.generic-capture.precise] + +r[type.impl-trait.generic-capture.precise.use] The set of generic parameters captured by a return-position `impl Trait` abstract type may be explicitly controlled with a [`use<..>` bound]. If present, only the generic parameters listed in the `use<..>` bound will be captured. E.g.: ```rust @@ -113,8 +142,13 @@ fn capture<'a, 'b, T>(x: &'a (), y: T) -> impl Sized + use<'a, T> { } ``` -Currently, only one `use<..>` bound may be present in a bounds list, such bounds are not allowed in the signature of items of a trait definition, all in-scope type and const generic parameters must be included, and all lifetime parameters that appear in other bounds of the abstract type must be included. Within the `use<..>` bound, any lifetime parameters present must appear before all type and const generic parameters, and the elided lifetime (`'_`) may be present if it is otherwise allowed to appear within the `impl Trait` return type. +r[type.impl-trait.generic-capture.precise.constraint-single] +Currently, only one `use<..>` bound may be present in a bounds list, such bounds are not allowed in the signature of items of a trait definition, all in-scope type and const generic parameters must be included, and all lifetime parameters that appear in other bounds of the abstract type must be included. +r[type.impl-trait.generic-capture.precise.constraint-lifetime] +Within the `use<..>` bound, any lifetime parameters present must appear before all type and const generic parameters, and the elided lifetime (`'_`) may be present if it is otherwise allowed to appear within the `impl Trait` return type. + +r[type.impl-trait.generic-capture.precise.constraint-param-impl-trait] Because all in-scope type parameters must be included by name, a `use<..>` bound may not be used in the signature of items that use argument-position `impl Trait`, as those items have anonymous type parameters in scope. ## Differences between generics and `impl Trait` in return position @@ -150,6 +184,8 @@ Instead, the function chooses the return type, but only promises that it will im ## Limitations +r[type.impl-trait.constraint] + `impl Trait` can only appear as a parameter or return type of a non-`extern` function. It cannot be the type of a `let` binding, field type, or appear inside a type alias. diff --git a/src/types/inferred.md b/src/types/inferred.md index c33ebd9..7179826 100644 --- a/src/types/inferred.md +++ b/src/types/inferred.md @@ -1,11 +1,19 @@ # Inferred type +r[type.inferred] + +r[type.inferred.syntax] > **Syntax**\ > _InferredType_ : `_` +r[type.inferred.intro] The inferred type asks the compiler to infer the type if possible based on the -surrounding information available. It cannot be used in item signatures. It is -often used in generic arguments: +surrounding information available. + +r[type.inferred.constraint] +It cannot be used in item signatures. + +It is often used in generic arguments: ```rust let x: Vec<_> = (0..10).collect(); diff --git a/src/types/never.md b/src/types/never.md index 7f58a3a..702281d 100644 --- a/src/types/never.md +++ b/src/types/never.md @@ -1,12 +1,19 @@ # Never type +r[type.never] + +r[type.never.syntax] > **Syntax**\ > _NeverType_ : `!` +r[type.never.intro] The never type `!` is a type with no values, representing the result of -computations that never complete. Expressions of type `!` can be coerced into -any other type. +computations that never complete. + +r[type.never.coercion] +Expressions of type `!` can be coerced into any other type. +r[type.never.constraint] The `!` type can **only** appear in function return types presently, indicating it is a diverging function that never returns. diff --git a/src/types/numeric.md b/src/types/numeric.md index bd59daa..88178d1 100644 --- a/src/types/numeric.md +++ b/src/types/numeric.md @@ -1,7 +1,12 @@ # Numeric types +r[type.numeric] + ## Integer types +r[type.numeric.int] + +r[type.numeric.int.unsigned] The unsigned integer types consist of: Type | Minimum | Maximum @@ -12,6 +17,7 @@ Type | Minimum | Maximum `u64` | 0 | 264-1 `u128` | 0 | 2128-1 +r[type.numeric.int.signed] The signed two's complement integer types consist of: Type | Minimum | Maximum @@ -25,20 +31,27 @@ Type | Minimum | Maximum ## Floating-point types +r[type.numeric.float] + The IEEE 754-2008 "binary32" and "binary64" floating-point types are `f32` and `f64`, respectively. ## Machine-dependent integer types +r[type.numeric.int.size] + +r[type.numeric.int.size.usize] The `usize` type is an unsigned integer type with the same number of bits as the platform's pointer type. It can represent every memory address in the process. +r[type.numeric.int.size.isize] The `isize` type is a signed 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 within an object along with one byte past the end. +r[type.numeric.int.size.minimum] `usize` and `isize` are at least 16-bits wide. > **Note**: Many pieces of Rust code may assume that pointers, `usize`, and @@ -48,5 +61,7 @@ within an object along with one byte past the end. ## Bit validity +r[type.numeric.validity] + For every numeric type, `T`, the bit validity of `T` is equivalent to the bit validity of `[u8; size_of::()]`. An uninitialized byte is not a valid `u8`. diff --git a/src/types/parameters.md b/src/types/parameters.md index 7b9e7e6..89b7df9 100644 --- a/src/types/parameters.md +++ b/src/types/parameters.md @@ -1,5 +1,7 @@ # Type parameters +r[type.generic] + Within the body of an item that has type parameter declarations, the names of its type parameters are types: diff --git a/src/types/pointer.md b/src/types/pointer.md index 7299ce7..0f24d6b 100644 --- a/src/types/pointer.md +++ b/src/types/pointer.md @@ -1,61 +1,96 @@ # Pointer types +r[type.pointer] + +r[type.pointer.intro] All pointers are explicit first-class values. They can be moved or copied, stored into data structs, and returned from functions. ## References (`&` and `&mut`) +r[type.pointer.reference] + +r[type.pointer.reference.syntax] > **Syntax**\ > _ReferenceType_ :\ >    `&` [_Lifetime_]? `mut`? [_TypeNoBounds_] ### Shared references (`&`) +r[type.pointer.reference.shared] + +r[type.pointer.reference.shared.intro] Shared references point to memory which is owned by some other value. + +r[type.pointer.reference.shared.constraint-mutation] When a shared reference to a value is created, it prevents direct mutation of the value. [Interior mutability] provides an exception for this in certain circumstances. As the name suggests, any number of shared references to a value may exist. A shared reference type is written `&type`, or `&'a type` when you need to specify an explicit lifetime. + +r[type.pointer.reference.shared.copy] Copying a reference is a "shallow" operation: it involves only copying the pointer itself, that is, pointers are `Copy`. Releasing a reference has no effect on the value it points to, but referencing of a [temporary value] will keep it alive during the scope of the reference itself. ### Mutable references (`&mut`) +r[type.pointer.reference.mut] + +r[type.pointer.reference.mut.intro] Mutable references point to memory which is owned by some other value. A mutable reference type is written `&mut type` or `&'a mut type`. + +r[type.pointer.reference.mut.copy] A mutable reference (that hasn't been borrowed) is the only way to access the value it points to, so is not `Copy`. ## Raw pointers (`*const` and `*mut`) +r[type.pointer.raw] + +r[type.pointer.raw.syntax] > **Syntax**\ > _RawPointerType_ :\ >    `*` ( `mut` | `const` ) [_TypeNoBounds_] +r[type.pointer.raw.intro] Raw pointers are pointers without safety or liveness guarantees. Raw pointers are written as `*const T` or `*mut T`. For example `*const i32` means a raw pointer to a 32-bit integer. + +r[type.pointer.raw.copy] Copying or dropping a raw pointer has no effect on the lifecycle of any other value. + +r[type.pointer.raw.safety] Dereferencing a raw pointer is an [`unsafe` operation]. + This can also be used to convert a raw pointer to a reference by reborrowing it (`&*` or `&mut *`). Raw pointers are generally discouraged; they exist to support interoperability with foreign code, and writing performance-critical or low-level functions. +r[type.pointer.raw.cmp] When comparing raw pointers they are compared by their address, rather than by what they point to. When comparing raw pointers to [dynamically sized types] they also have their additional data compared. +r[type.pointer.raw.constructor] Raw pointers can be created directly using `&raw const` for `*const` pointers and `&raw mut` for `*mut` pointers. ## Smart Pointers +r[type.pointer.smart] + The standard library contains additional 'smart pointer' types beyond references and raw pointers. ## Bit validity +r[type.pointer.validity] + +r[type.pointer.validity.pointer-fragment] Despite pointers and references being similar to `usize`s in the machine code emitted on most platforms, the semantics of transmuting a reference or pointer type to a non-pointer type is currently undecided. Thus, it may not be valid to transmute a pointer or reference type, `P`, to a `[u8; size_of::

    ()]`. +r[type.pointer.validity.raw] For thin raw pointers (i.e., for `P = *const T` or `P = *mut T` for `T: Sized`), the inverse direction (transmuting from an integer or array of integers to `P`) is always valid. However, the pointer produced via such a transmutation may not be dereferenced (not even if `T` has size zero). diff --git a/src/types/slice.md b/src/types/slice.md index 6ba5e7d..79c340a 100644 --- a/src/types/slice.md +++ b/src/types/slice.md @@ -1,12 +1,17 @@ # Slice types +r[type.slice] + +r[type.slice.syntax] > **Syntax**\ > _SliceType_ :\ >    `[` [_Type_] `]` +r[type.slice.intro] A slice is a [dynamically sized type] representing a 'view' into a sequence of elements of type `T`. The slice type is written as `[T]`. +r[type.slice.unsized] Slice types are generally used through pointer types. For example: * `&[T]`: a 'shared slice', often just called a 'slice'. It doesn't own the @@ -24,6 +29,7 @@ let boxed_array: Box<[i32]> = Box::new([1, 2, 3]); let slice: &[i32] = &boxed_array[..]; ``` +r[type.slice.safe] All elements of slices are always initialized, and access to a slice is always bounds-checked in safe methods and operators. diff --git a/src/types/struct.md b/src/types/struct.md index 1f20dbb..6a672f7 100644 --- a/src/types/struct.md +++ b/src/types/struct.md @@ -1,22 +1,30 @@ # Struct types +r[type.struct] + +r[type.struct.intro] A `struct` *type* is a heterogeneous product of other types, called the *fields* of the type.[^structtype] +r[type.struct.constructor] New instances of a `struct` can be constructed with a [struct expression]. +r[type.struct.layout] The memory layout of a `struct` is undefined by default to allow for compiler optimizations like field reordering, but it can be fixed with the [`repr` attribute]. In either case, fields may be given in any order in a corresponding struct *expression*; the resulting `struct` value will always have the same memory layout. +r[type.struct.field-visibility] The fields of a `struct` may be qualified by [visibility modifiers], to allow access to data in a struct outside a module. +r[type.struct.tuple] A _tuple struct_ type is just like a struct type, except that the fields are anonymous. +r[type.struct.unit] A _unit-like struct_ type is like a struct type, except that it has no fields. The one value constructed by the associated [struct expression] is the only value that inhabits such a type. diff --git a/src/types/textual.md b/src/types/textual.md index a4765b5..8f2c97a 100644 --- a/src/types/textual.md +++ b/src/types/textual.md @@ -1,26 +1,39 @@ # Textual types +r[type.text] + +r[type.text.intro] The types `char` and `str` hold textual data. +r[type.text.char-value] A value of type `char` is a [Unicode scalar value] (i.e. a code point that is not a surrogate), represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF -or 0xE000 to 0x10FFFF range. It is immediate [undefined behavior] to create a +or 0xE000 to 0x10FFFF range. + +r[type.text.char-precondition] +It is immediate [undefined behavior] to create a `char` that falls outside this range. A `[char]` is effectively a UCS-4 / UTF-32 string of length 1. +r[type.text.str-value] A value of type `str` is represented the same way as `[u8]`, a slice of 8-bit unsigned bytes. However, the Rust standard library makes extra assumptions about `str`: methods working on `str` assume and ensure that the data in there is valid UTF-8. Calling a `str` method with a non-UTF-8 buffer can cause [undefined behavior] now or in the future. +r[type.text.str-unsized] Since `str` is a [dynamically sized type], it can only be instantiated through a pointer type, such as `&str`. ## Layout and bit validity +r[type.text.layout] + +r[type.layout.char-layout] `char` is guaranteed to have the same size and alignment as `u32` on all platforms. +r[type.layout.char-validity] Every byte of a `char` is guaranteed to be initialized (in other words, `transmute::()]>(...)` is always sound -- but since some bit patterns are invalid `char`s, the inverse is not always sound). diff --git a/src/types/trait-object.md b/src/types/trait-object.md index 5b8541f..598ad29 100644 --- a/src/types/trait-object.md +++ b/src/types/trait-object.md @@ -1,5 +1,8 @@ # Trait objects +r[type.trait-object] + +r[type.trait-object.syntax] > **Syntax**\ > _TraitObjectType_ :\ >    `dyn`? [_TypeParamBounds_] @@ -7,16 +10,21 @@ > _TraitObjectTypeOneBound_ :\ >    `dyn`? [_TraitBound_] +r[type.trait-object.intro] A *trait object* is an opaque value of another type that implements a set of traits. The set of traits is made up of an [object safe] *base trait* plus any number of [auto traits]. +r[type.trait-object.impls] Trait objects implement the base trait, its auto traits, and any [supertraits] of the base trait. +r[type.trait-object.name] Trait objects are written as the keyword `dyn` followed by a set of trait -bounds, but with the following restrictions on the trait bounds. All traits -except the first trait must be auto traits, there may not be more than one +bounds, but with the following restrictions on the trait bounds. + +r[type.trait-object.constraint] +All traits except the first trait must be auto traits, there may not be more than one lifetime, and opt-out bounds (e.g. `?Sized`) are not allowed. Furthermore, paths to traits may be parenthesized. @@ -31,12 +39,14 @@ For example, given a trait `Trait`, the following are all trait objects: * `dyn 'static + Trait`. * `dyn (Trait)` +r[type.trait-object.syntax-edition2021] > **Edition differences**: Before the 2021 edition, the `dyn` keyword may be > omitted. > > Note: For clarity, it is recommended to always use the `dyn` keyword on your > trait objects unless your codebase supports compiling with Rust 1.26 or lower. +r[type.trait-object.syntax-edition2015] > **Edition differences**: In the 2015 edition, if the first bound of the > trait object is a path that starts with `::`, then the `dyn` will be treated > as a part of the path. The first path can be put in parenthesis to get @@ -46,11 +56,13 @@ For example, given a trait `Trait`, the following are all trait objects: > Beginning in the 2018 edition, `dyn` is a true keyword and is not allowed in > paths, so the parentheses are not necessary. +r[type.trait-object.alias] Two trait object types alias each other if the base traits alias each other and if the sets of auto traits are the same and the lifetime bounds are the same. For example, `dyn Trait + Send + UnwindSafe` is the same as `dyn Trait + UnwindSafe + Send`. +r[type.trait-object.unsized] Due to the opaqueness of which concrete type the value is of, trait objects are [dynamically sized types]. Like all DSTs, trait objects are used @@ -93,6 +105,8 @@ type signature of `print`, and the cast expression in `main`. ## Trait Object Lifetime Bounds +r[type.trait-object.lifetime-bounds] + Since a trait object can contain references, the lifetimes of those references need to be expressed as part of the trait object. This lifetime is written as `Trait + 'a`. There are [defaults] that allow this lifetime to usually be diff --git a/src/types/tuple.md b/src/types/tuple.md index 804d8a0..073fbd1 100644 --- a/src/types/tuple.md +++ b/src/types/tuple.md @@ -1,26 +1,35 @@ # Tuple types +r[type.tuple] + +r[type.tuple.syntax] > **Syntax**\ > _TupleType_ :\ >       `(` `)`\ >    | `(` ( [_Type_] `,` )+ [_Type_]? `)` +r[type.tuple.intro] *Tuple types* are a family of structural types[^1] for heterogeneous lists of other types. The syntax for a tuple type is a parenthesized, comma-separated list of types. + +r[type.tuple.restriction] 1-ary tuples require a comma after their element type to be disambiguated with a [parenthesized type]. +r[type.tuple.field-number] A tuple type has a number of fields equal to the length of the list of types. This number of fields determines the *arity* of the tuple. A tuple with `n` fields is called an *n-ary tuple*. For example, a tuple with 2 fields is a 2-ary tuple. +r[type.tuple.field-name] Fields of tuples are named using increasing numeric names matching their position in the list of types. The first field is `0`. The second field is `1`. And so on. The type of each field is the type of the same position in the tuple's list of types. +r[type.tuple.unit] For convenience and historical reasons, the tuple type with no fields (`()`) is often called *unit* or *the unit type*. Its one value is also called *unit* or *the unit value*. @@ -33,8 +42,11 @@ Some examples of tuple types: * `(i32, String)` (different type from the previous example) * `(i32, f64, Vec, Option)` +r[type.tuple.constructor] Values of this type are constructed using a [tuple expression]. Furthermore, various expressions will produce the unit value if there is no other meaningful value for it to evaluate to. + +r[type.tuple.access] Tuple fields can be accessed by either a [tuple index expression] or [pattern matching]. [^1]: Structural types are always equivalent if their internal types are equivalent. diff --git a/src/types/union.md b/src/types/union.md index 7a2f037..c8801ee 100644 --- a/src/types/union.md +++ b/src/types/union.md @@ -1,15 +1,25 @@ # Union types +r[type.union] + +r[type.union.intro] A *union type* is a nominal, heterogeneous C-like union, denoted by the name of a [`union` item][item]. +r[type.union.access] Unions have no notion of an "active field". Instead, every union access transmutes parts of the content of the union to the type of the accessed field. + +r[type.union.safety] Since transmutes can cause unexpected or undefined behaviour, `unsafe` is -required to read from a union field. Union field types are also restricted to a +required to read from a union field. + +r[type.union.constraint] +Union field types are also restricted to a subset of types which ensures that they never need dropping. See the [item] documentation for further details. +r[type.union.layout] The memory layout of a `union` is undefined by default (in particular, fields do *not* have to be at offset 0), but the `#[repr(...)]` attribute can be used to fix a layout. From ce1c5fa518ad7e23a6cd95f1f7390f334df21717 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 18 Sep 2024 21:43:10 -0400 Subject: [PATCH 076/189] Remove extraneous trailing whitespace --- src/types/function-item.md | 2 +- src/types/impl-trait.md | 4 ++-- src/types/textual.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types/function-item.md b/src/types/function-item.md index ef51285..3aa5a24 100644 --- a/src/types/function-item.md +++ b/src/types/function-item.md @@ -4,7 +4,7 @@ r[type.fn-item] r[type.fn-item.intro] When referred to, a function item, or the constructor of a tuple-like struct or -enum variant, yields a zero-sized value of its _function item type_. +enum variant, yields a zero-sized value of its _function item type_\1 r[type.fn-item.unique] That type explicitly identifies the function - its name, its type arguments, and its diff --git a/src/types/impl-trait.md b/src/types/impl-trait.md index a661837..5a91334 100644 --- a/src/types/impl-trait.md +++ b/src/types/impl-trait.md @@ -122,7 +122,7 @@ r[type.impl-trait.generic-capture.auto.intro] Return-position `impl Trait` abstract types automatically capture certain of the in-scope generic parameters. Everywhere, these automatically capture all in-scope type and const generic parameters. r[type.impl-trait.generic-capture.auto.trait] -On items of trait impls and trait definitions, these types additionally automatically capture all in-scope generic lifetime parameters, including higher-ranked ones. +On items of trait impls and trait definitions, these types additionally automatically capture all in-scope generic lifetime parameters, including higher-ranked ones\1 r[type.impl-trait.generic-capture.auto.fn] On free functions and on associated functions and methods of inherent impls, only the generic lifetime parameters that appear in the bounds of abstract return type are captured. @@ -143,7 +143,7 @@ fn capture<'a, 'b, T>(x: &'a (), y: T) -> impl Sized + use<'a, T> { ``` r[type.impl-trait.generic-capture.precise.constraint-single] -Currently, only one `use<..>` bound may be present in a bounds list, such bounds are not allowed in the signature of items of a trait definition, all in-scope type and const generic parameters must be included, and all lifetime parameters that appear in other bounds of the abstract type must be included. +Currently, only one `use<..>` bound may be present in a bounds list, such bounds are not allowed in the signature of items of a trait definition, all in-scope type and const generic parameters must be included, and all lifetime parameters that appear in other bounds of the abstract type must be included\1 r[type.impl-trait.generic-capture.precise.constraint-lifetime] Within the `use<..>` bound, any lifetime parameters present must appear before all type and const generic parameters, and the elided lifetime (`'_`) may be present if it is otherwise allowed to appear within the `impl Trait` return type. diff --git a/src/types/textual.md b/src/types/textual.md index 8f2c97a..e851533 100644 --- a/src/types/textual.md +++ b/src/types/textual.md @@ -11,7 +11,7 @@ not a surrogate), represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF or 0xE000 to 0x10FFFF range. r[type.text.char-precondition] -It is immediate [undefined behavior] to create a +It is immediate [undefined behavior] to create \1 `char` that falls outside this range. A `[char]` is effectively a UCS-4 / UTF-32 string of length 1. From 4d7609bcfba9efe02d86b365469a4a9d9ece7e8b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 18 Sep 2024 21:55:47 -0400 Subject: [PATCH 077/189] Apply suggestions from code review Co-authored-by: Travis Cross --- docs/authoring.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/authoring.md b/docs/authoring.md index 5fbbbe9..d64fb21 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -78,12 +78,12 @@ In the HTML, the rules are clickable just like headers. When assigning rules to new paragraphs, or when modifying rule names, use the following guidelines: 1. A rule applies to one core idea, which should be easily determined when reading the paragraph it is applied to, 2. Other than the "intro" paragraph, purely explanatory, expository, or exemplary content does not need a rule. If the expository paragraph isn't directly related to the previous, separate it with a hard (rendered) line break -3. Rust Code examples and tests do not need their own rules +3. Rust code examples and tests do not need their own rules 4. Notes do not need rules. For other admonition types, use the following guidelines: * Warning: Omit the rule if and only if the warning follows from the previous paragraph. - * Target Specific Behaviour: Always include the rule - * Edition Differences: Always include the rule - * Version History: Omit the rule if the present behaviour is explained in the immediately preceeding rule. + * Target specific behaviour: Always include the rule + * Edition differences: Always include the rule + * Version history: Omit the rule if the present behaviour is explained in the immediately preceeding rule. 4. The following keywords should be used to identify paragraphs when unambiguous: * `intro`: The beginning paragraph of each section - should explain the construct being defined overall. * `syntax`: Syntax definitions or explanations when BNF syntax definitions are not used @@ -95,7 +95,7 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo * `preconditions`: Conditions which must be satisfied for the evaluation of the construct to be well-defined * `namespace`: For items only, specifies the namespace(s) the item introduces a name in. May also be used elsewhere when defining a namespace (e.g. `r[attribute.diagnostic.namespace]`) 5. When a rule doesn't fall under the above keywords. or for section rule ids, name the subrule as follows: - * If the rule is naming a specific Rust language construct (IE. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s) + * If the rule is naming a specific Rust language construct (e.g. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s) * Other than rust language concepts with `_`s in the name, use `-` characters to separate words within a "subrule" * Whenever possible, do not repeat previous components of the rule * Prefer using singular forms of words over plural unless the rule applies to a list or the construct is named as plural in the language (e.g. `r[attribute.diagnostic.lint.group]) From 02ba9ff233047177dbea39cf0cae1129c12f50a6 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 19 Sep 2024 09:05:29 -0400 Subject: [PATCH 078/189] Fix compilation issues in mdbook FIXME: Error with `r[type.closure.capture.composite]` but the rule seems to be wf? --- src/types/array.md | 2 +- src/types/closure.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/types/array.md b/src/types/array.md index a5211cb..ef54af1 100644 --- a/src/types/array.md +++ b/src/types/array.md @@ -7,7 +7,7 @@ r[type.array.syntax] > _ArrayType_ :\ >    `[` [_Type_] `;` [_Expression_] `]` -r[type.array.index] +r[type.array.intro] An array is a fixed-size sequence of `N` elements of type `T`. The array type is written as `[T; N]`. diff --git a/src/types/closure.md b/src/types/closure.md index d6833ed..7768ceb 100644 --- a/src/types/closure.md +++ b/src/types/closure.md @@ -65,10 +65,11 @@ types, by copy, regardless of whether a borrow would work. The `move` keyword is usually used to allow the closure to outlive the captured values, such as if the closure is being returned or used to spawn a new thread. -r[type.closure.capture.composite] +r[type.closure.capture.composite] Composite types such as structs, tuples, and enums are always captured entirely, not by individual fields. It may be necessary to borrow into a local variable in order to capture a single field: + ```rust # use std::collections::HashSet; From 56c5e072545ffdbfb420b6a9784cdba058fa706e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 19 Sep 2024 09:15:21 -0400 Subject: [PATCH 079/189] Add spec identifier syntax to `unsafe-keyword.md` and `unsafety.md` --- src/unsafe-keyword.md | 22 ++++++++++++++++++++++ src/unsafety.md | 17 +++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/unsafe-keyword.md b/src/unsafe-keyword.md index 0206d87..232fcca 100644 --- a/src/unsafe-keyword.md +++ b/src/unsafe-keyword.md @@ -1,5 +1,8 @@ # The `unsafe` keyword +r[unsafe] + +r[unsafe.intro] The `unsafe` keyword can occur in several different contexts: unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), unsafe trait implementations (`unsafe impl`), unsafe external blocks (`unsafe extern`), and unsafe attributes (`#[unsafe(attr)]`). It plays several different roles, depending on where it is used and whether the `unsafe_op_in_unsafe_fn` lint is enabled: @@ -11,16 +14,25 @@ See the [keyword documentation][keyword] for some illustrative examples. ## Unsafe functions (`unsafe fn`) +r[unsafe.fn] + +r[unsafe.fn.intro] Unsafe functions are functions that are not safe in all contexts and/or for all possible inputs. We say they have *extra safety conditions*, which are requirements that must be upheld by all callers and that the compiler does not check. For example, [`get_unchecked`] has the extra safety condition that the index must be in-bounds. The unsafe function should come with documentation explaining what those extra safety conditions are. +r[unsafe.fn.safety] Such a function must be prefixed with the keyword `unsafe` and can only be called from inside an `unsafe` block, or inside `unsafe fn` without the [`unsafe_op_in_unsafe_fn`] lint. ## Unsafe blocks (`unsafe {}`) +r[unsafe.block] + +r[unsafe.block.intro] A block of code can be prefixed with the `unsafe` keyword, to permit calling `unsafe` functions or dereferencing raw pointers. + +r[unsafe.block.fn-body] By default, the body of an unsafe function is also considered to be an unsafe block; this can be changed by enabling the [`unsafe_op_in_unsafe_fn`] lint. @@ -41,13 +53,19 @@ By using `unsafe` blocks to represent the reverse links as raw pointers, it can ## Unsafe traits (`unsafe trait`) +r[unsafe.trait] + +r[unsafe.trait.intro] An unsafe trait is a trait that comes with extra safety conditions that must be upheld by *implementations* of the trait. The unsafe trait should come with documentation explaining what those extra safety conditions are. +r[unsafe.trait.safety] Such a trait must be prefixed with the keyword `unsafe` and can only be implemented by `unsafe impl` blocks. ## Unsafe trait implementations (`unsafe impl`) +r[unsafe.impl] + When implementing an unsafe trait, the implementation needs to be prefixed with the `unsafe` keyword. By writing `unsafe impl`, the programmer states that they have taken care of satisfying the extra safety conditions required by the trait. @@ -59,12 +77,16 @@ Unsafe trait implementations are the logical dual to unsafe traits: where unsafe ## Unsafe external blocks (`unsafe extern`) +r[unsafe.extern] + The programmer who declares an [external block] must assure that the signatures of the items contained within are correct. Failing to do so may lead to undefined behavior. That this obligation has been met is indicated by writing `unsafe extern`. [external block]: items/external-blocks.md ## Unsafe attributes (`#[unsafe(attr)]`) +r[unsafe.attribute] + An [unsafe attribute] is one that has extra safety conditions that must be upheld when using the attribute. The compiler cannot check whether these conditions have been upheld. To assert that they have been, these attributes must be wrapped in `unsafe(..)`, e.g. `#[unsafe(no_mangle)]`. [unsafe attribute]: attributes.md diff --git a/src/unsafety.md b/src/unsafety.md index 9383eba..daa6834 100644 --- a/src/unsafety.md +++ b/src/unsafety.md @@ -1,17 +1,34 @@ # Unsafety +r[safety] + +r[safety.intro] Unsafe operations are those that can potentially violate the memory-safety guarantees of Rust's static semantics. +r[safety.unsafe-ops] The following language level features cannot be used in the safe subset of Rust: +r[safety.unsafe-deref] - Dereferencing a [raw pointer]. + +r[safety.unsafe-static] - Reading or writing a [mutable] or [external] static variable. + +r[safety.unsafe-union-access] - Accessing a field of a [`union`], other than to assign to it. + +r[safety.unsafe-call] - Calling an unsafe function (including an intrinsic or foreign function). + +r[safety.unsafe-impl] - Implementing an [unsafe trait]. + +r[safety.unsafe-extern] - Declaring an [`extern`] block. + +r[safety.unsafe-attribute] - Applying an [unsafe attribute] to an item. [`extern`]: items/external-blocks.md From 2826c689851691d147df37460c6e50c7d3ffd865 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 19 Sep 2024 10:19:53 -0400 Subject: [PATCH 080/189] Add identifier syntax to lexer chapters --- src/lexical-structure.md | 2 + src/tokens.md | 135 ++++++++++++++++++++++++++++++++++++++- src/whitespace.md | 5 ++ 3 files changed, 140 insertions(+), 2 deletions(-) diff --git a/src/lexical-structure.md b/src/lexical-structure.md index 5e1388e..ac64c78 100644 --- a/src/lexical-structure.md +++ b/src/lexical-structure.md @@ -1 +1,3 @@ # Lexical structure + + \ No newline at end of file diff --git a/src/tokens.md b/src/tokens.md index d94464f..ef914a1 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -1,5 +1,8 @@ # Tokens +r[lex.token] + +r[lex.token.intro] Tokens are primitive productions in the grammar defined by regular (non-recursive) languages. Rust source input can be broken down into the following kinds of tokens: @@ -18,6 +21,7 @@ table production] form, and appear in `monospace` font. ## Literals +r[lex.token.literal] Literals are tokens used in [literal expressions]. ### Examples @@ -88,13 +92,17 @@ Literals are tokens used in [literal expressions]. #### Suffixes -A suffix is a sequence of characters following the primary part of a literal (without intervening whitespace), of the same form as a non-raw identifier or keyword. +r[lex.token.literal.suffix] +r[lex.token.literal.literal.suffix.intro] +A suffix is a sequence of characters following the primary part of a literal (without intervening whitespace), of the same form as a non-raw identifier or keyword. +r[lex.token.literal.suffix.syntax] > **Lexer**\ > SUFFIX : IDENTIFIER_OR_KEYWORD\ > SUFFIX_NO_E : SUFFIX _not beginning with `e` or `E`_ +r[lex.token.literal.suffix.validity] Any kind of literal (string, integer, etc) with any suffix is valid as a token. A literal token with any suffix can be passed to a macro without producing an error. @@ -109,6 +117,7 @@ blackhole!("string"suffix); // OK blackhole_lit!(1suffix); // OK ``` +r[lex.token.literal.suffix.parse] However, suffixes on literal tokens which are interpreted as literal expressions or patterns are restricted. Any suffixes are rejected on non-numeric literal tokens, and numeric literal tokens are accepted only with suffixes from the list below. @@ -121,6 +130,9 @@ and numeric literal tokens are accepted only with suffixes from the list below. #### Character literals +r[lex.token.literal.char] + +r[lex.token.literal.char.syntax] > **Lexer**\ > CHAR_LITERAL :\ >    `'` ( ~\[`'` `\` \\n \\r \\t] | QUOTE_ESCAPE | ASCII_ESCAPE | UNICODE_ESCAPE ) `'` SUFFIX? @@ -135,12 +147,16 @@ and numeric literal tokens are accepted only with suffixes from the list below. > UNICODE_ESCAPE :\ >    `\u{` ( HEX_DIGIT `_`\* )1..6 `}` +r[lex.token.literal.char.intro] A _character literal_ is a single Unicode character enclosed within two `U+0027` (single-quote) characters, with the exception of `U+0027` itself, which must be _escaped_ by a preceding `U+005C` character (`\`). #### String literals +r[lex.token.literal.str] + +r[lex.token.literal.str.syntax] > **Lexer**\ > STRING_LITERAL :\ >    `"` (\ @@ -154,10 +170,12 @@ which must be _escaped_ by a preceding `U+005C` character (`\`). > STRING_CONTINUE :\ >    `\` _followed by_ \\n +r[lex.token.literal.str.intro] A _string literal_ is a sequence of any Unicode characters enclosed within two `U+0022` (double-quote) characters, with the exception of `U+0022` itself, which must be _escaped_ by a preceding `U+005C` character (`\`). +r[lex.token.literal.str.linefeed] Line-breaks, represented by the character `U+000A` (LF), are allowed in string literals. When an unescaped `U+005C` character (`\`) occurs immediately before a line break, the line break does not appear in the string represented by the token. See [String continuation escapes] for details. @@ -165,28 +183,43 @@ The character `U+000D` (CR) may not appear in a string literal other than as par #### Character escapes +r[lex.token.literal.char-escape] + +r[lex.token.literal.char-escape.intro] Some additional _escapes_ are available in either character or non-raw string literals. An escape starts with a `U+005C` (`\`) and continues with one of the following forms: +r[lex.token.literal.char-escape.ascii] * A _7-bit code point escape_ starts with `U+0078` (`x`) and is followed by exactly two _hex digits_ with value up to `0x7F`. It denotes the ASCII character with value equal to the provided hex value. Higher values are not permitted because it is ambiguous whether they mean Unicode code points or byte values. + +r[lex.token.literal.char-escape.unicode] * A _24-bit code point escape_ starts with `U+0075` (`u`) and is followed by up to six _hex digits_ surrounded by braces `U+007B` (`{`) and `U+007D` (`}`). It denotes the Unicode code point equal to the provided hex value. + +r[lex.token.literal.char-escape.whitespace] * A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072` (`r`), or `U+0074` (`t`), denoting the Unicode values `U+000A` (LF), `U+000D` (CR) or `U+0009` (HT) respectively. + +r[lex.token.literal.char-escape.null] * The _null escape_ is the character `U+0030` (`0`) and denotes the Unicode value `U+0000` (NUL). + +r[lex.token.literal.char-escape.slash] * The _backslash escape_ is the character `U+005C` (`\`) which must be escaped in order to denote itself. #### Raw string literals +r[lex.token.literal.str-raw] + +r[lex.token.literal.str-raw.syntax] > **Lexer**\ > RAW_STRING_LITERAL :\ >    `r` RAW_STRING_CONTENT SUFFIX? @@ -195,13 +228,16 @@ following forms: >       `"` ( ~ _IsolatedCR_ )* (non-greedy) `"`\ >    | `#` RAW_STRING_CONTENT `#` +r[lex.token.literal.str-raw.intro] Raw string literals do not process any escapes. They start with the character `U+0072` (`r`), followed by fewer than 256 of the character `U+0023` (`#`) and a `U+0022` (double-quote) character. +r[lex.token.literal.str-raw.body] The _raw string body_ can contain any sequence of Unicode characters other than `U+000D` (CR). It is terminated only by another `U+0022` (double-quote) character, followed by the same number of `U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote) character. +r[lex.token.literal.str-raw.content] All Unicode characters contained in the raw string body represent themselves, the characters `U+0022` (double-quote) (except when followed by at least as many `U+0023` (`#`) characters as were used to start the raw string literal) or @@ -224,6 +260,9 @@ r##"foo #"# bar"##; // foo #"# bar #### Byte literals +r[lex.token.byte] + +r[lex.token.byte.syntax] > **Lexer**\ > BYTE_LITERAL :\ >    `b'` ( ASCII_FOR_CHAR | BYTE_ESCAPE ) `'` SUFFIX? @@ -235,6 +274,7 @@ r##"foo #"# bar"##; // foo #"# bar >       `\x` HEX_DIGIT HEX_DIGIT\ >    | `\n` | `\r` | `\t` | `\\` | `\0` | `\'` | `\"` +r[lex.token.byte.intro] A _byte literal_ is a single ASCII character (in the `U+0000` to `U+007F` range) or a single _escape_ preceded by the characters `U+0062` (`b`) and `U+0027` (single-quote), and followed by the character `U+0027`. If the character @@ -244,6 +284,9 @@ _number literal_. #### Byte string literals +r[lex.token.str-byte] + +r[lex.token.str-byte.syntax] > **Lexer**\ > BYTE_STRING_LITERAL :\ >    `b"` ( ASCII_FOR_STRING | BYTE_ESCAPE | STRING_CONTINUE )\* `"` SUFFIX? @@ -251,6 +294,7 @@ _number literal_. > ASCII_FOR_STRING :\ >    _any ASCII (i.e 0x00 to 0x7F), except_ `"`, `\` _and IsolatedCR_ +r[lex.token.str-byte.intro] A non-raw _byte string literal_ is a sequence of ASCII characters and _escapes_, preceded by the characters `U+0062` (`b`) and `U+0022` (double-quote), and followed by the character `U+0022`. If the character `U+0022` is present within @@ -258,28 +302,40 @@ the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character. Alternatively, a byte string literal can be a _raw byte string literal_, defined below. +r[lex.token.str-byte.linefeed] Line-breaks, represented by the character `U+000A` (LF), are allowed in byte string literals. When an unescaped `U+005C` character (`\`) occurs immediately before a line break, the line break does not appear in the string represented by the token. See [String continuation escapes] for details. The character `U+000D` (CR) may not appear in a byte string literal other than as part of such a string continuation escape. +r[lex.token.str-byte.escape] Some additional _escapes_ are available in either byte or non-raw byte string literals. An escape starts with a `U+005C` (`\`) and continues with one of the following forms: +r[lex.token.str-byte.escape-byte] * A _byte escape_ escape starts with `U+0078` (`x`) and is followed by exactly two _hex digits_. It denotes the byte equal to the provided hex value. + +r[lex.token.str-byte.escape-whitespace] * A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072` (`r`), or `U+0074` (`t`), denoting the bytes values `0x0A` (ASCII LF), `0x0D` (ASCII CR) or `0x09` (ASCII HT) respectively. + +r[lex.token.str-byte.escape-null] * The _null escape_ is the character `U+0030` (`0`) and denotes the byte value `0x00` (ASCII NUL). + +r[lex.token.str-byte.escape-slash] * The _backslash escape_ is the character `U+005C` (`\`) which must be escaped in order to denote its ASCII encoding `0x5C`. #### Raw byte string literals +r[lex.token.str-byte-raw] + +r[lex.token.str-byte-raw.syntax] > **Lexer**\ > RAW_BYTE_STRING_LITERAL :\ >    `br` RAW_BYTE_STRING_CONTENT SUFFIX? @@ -291,14 +347,17 @@ following forms: > ASCII_FOR_RAW :\ >    _any ASCII (i.e. 0x00 to 0x7F) except IsolatedCR_ +r[lex.token.str-byte-raw.intro] Raw byte string literals do not process any escapes. They start with the character `U+0062` (`b`), followed by `U+0072` (`r`), followed by fewer than 256 of the character `U+0023` (`#`), and a `U+0022` (double-quote) character. +r[lex.token.str-byte-raw.body] The _raw string body_ can contain any sequence of ASCII characters other than `U+000D` (CR). It is terminated only by another `U+0022` (double-quote) character, followed by the same number of `U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote) character. A raw byte string literal can not contain any non-ASCII byte. +r[lex.token.literal.str-raw.content] All characters contained in the raw string body represent their ASCII encoding, the characters `U+0022` (double-quote) (except when followed by at least as many `U+0023` (`#`) characters as were used to start the raw string literal) or @@ -321,6 +380,9 @@ b"\\x52"; br"\x52"; // \x52 #### C string literals +r[lex.token.str-c] + +r[lex.token.str-c.syntax] > **Lexer**\ > C_STRING_LITERAL :\ >    `c"` (\ @@ -330,6 +392,7 @@ b"\\x52"; br"\x52"; // \x52 >       | STRING_CONTINUE\ >    )\* `"` SUFFIX? +r[lex.token.str-c.intro] A _C string literal_ is a sequence of Unicode characters and _escapes_, preceded by the characters `U+0063` (`c`) and `U+0022` (double-quote), and followed by the character `U+0022`. If the character `U+0022` is present within @@ -338,31 +401,42 @@ Alternatively, a C string literal can be a _raw C string literal_, defined below [CStr]: core::ffi::CStr +r[lex.token.str-c.null] C strings are implicitly terminated by byte `0x00`, so the C string literal `c""` is equivalent to manually constructing a `&CStr` from the byte string literal `b"\x00"`. Other than the implicit terminator, byte `0x00` is not permitted within a C string. +r[lex.token.str-c.linefeed] Line-breaks, represented by the character `U+000A` (LF), are allowed in C string literals. When an unescaped `U+005C` character (`\`) occurs immediately before a line break, the line break does not appear in the string represented by the token. See [String continuation escapes] for details. The character `U+000D` (CR) may not appear in a C string literal other than as part of such a string continuation escape. +r[lex.token.str-c.escape] Some additional _escapes_ are available in non-raw C string literals. An escape starts with a `U+005C` (`\`) and continues with one of the following forms: +r[lex.token.str-c.escape-byte] * A _byte escape_ escape starts with `U+0078` (`x`) and is followed by exactly two _hex digits_. It denotes the byte equal to the provided hex value. + +r[lex.token.str-c.escape-unicode] * A _24-bit code point escape_ starts with `U+0075` (`u`) and is followed by up to six _hex digits_ surrounded by braces `U+007B` (`{`) and `U+007D` (`}`). It denotes the Unicode code point equal to the provided hex value, encoded as UTF-8. + +r[lex.token.str-c.escape-whitespace] * A _whitespace escape_ is one of the characters `U+006E` (`n`), `U+0072` (`r`), or `U+0074` (`t`), denoting the bytes values `0x0A` (ASCII LF), `0x0D` (ASCII CR) or `0x09` (ASCII HT) respectively. + +r[lex.token.str-c.escape-slash] * The _backslash escape_ is the character `U+005C` (`\`) which must be escaped in order to denote its ASCII encoding `0x5C`. +r[lex.token.str-c.char-unicode] A C string represents bytes with no defined encoding, but a C string literal may contain Unicode characters above `U+007F`. Such characters will be replaced with the bytes of that character's UTF-8 representation. @@ -375,11 +449,15 @@ c"\u{00E6}"; c"\xC3\xA6"; ``` +r[lex.token.str-c.edition2021] > **Edition differences**: C string literals are accepted in the 2021 edition or > later. In earlier additions the token `c""` is lexed as `c ""`. #### Raw C string literals +r[lex.token.str-c-raw] + +r[lex.token.str-c-raw.syntax] > **Lexer**\ > RAW_C_STRING_LITERAL :\ >    `cr` RAW_C_STRING_CONTENT SUFFIX? @@ -388,18 +466,22 @@ c"\xC3\xA6"; >       `"` ( ~ _IsolatedCR_ _NUL_ )* (non-greedy) `"`\ >    | `#` RAW_C_STRING_CONTENT `#` +r[lex.token.str-c-raw.intro] Raw C string literals do not process any escapes. They start with the character `U+0063` (`c`), followed by `U+0072` (`r`), followed by fewer than 256 of the character `U+0023` (`#`), and a `U+0022` (double-quote) character. +r[lex.token.str-c-raw.body] The _raw C string body_ can contain any sequence of Unicode characters other than `U+0000` (NUL) and `U+000D` (CR). It is terminated only by another `U+0022` (double-quote) character, followed by the same number of `U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote) character. +r[lex.token.str-c-raw.content] All characters contained in the raw C string body represent themselves in UTF-8 encoding. The characters `U+0022` (double-quote) (except when followed by at least as many `U+0023` (`#`) characters as were used to start the raw C string literal) or `U+005C` (`\`) do not have any special meaning. +r[lex.token.str-c-raw.edition2021] > **Edition differences**: Raw C string literals are accepted in the 2021 > edition or later. In earlier additions the token `cr""` is lexed as `cr ""`, > and `cr#""#` is lexed as `cr #""#` (which is non-grammatical). @@ -419,11 +501,16 @@ c"\\x52"; cr"\x52"; // \x52 ### Number literals +r[lex.token.literal.num] + A _number literal_ is either an _integer literal_ or a _floating-point literal_. The grammar for recognizing the two kinds of literals is mixed. #### Integer literals +r[lex.token.literal.int] + +r[lex.token.literal.int.syntax] > **Lexer**\ > INTEGER_LITERAL :\ >    ( DEC_LITERAL | BIN_LITERAL | OCT_LITERAL | HEX_LITERAL ) @@ -449,20 +536,29 @@ literal_. The grammar for recognizing the two kinds of literals is mixed. > > HEX_DIGIT : \[`0`-`9` `a`-`f` `A`-`F`] +r[lex.token.literal.int.kind] An _integer literal_ has one of four forms: +r[lex.token.literal.int.kind-dec] * A _decimal literal_ starts with a *decimal digit* and continues with any mixture of *decimal digits* and _underscores_. + +r[lex.token.literal.int.kind-hex] * A _hex literal_ starts with the character sequence `U+0030` `U+0078` (`0x`) and continues as any mixture (with at least one digit) of hex digits and underscores. + +r[lex.token.literal.int.kind-oct] * An _octal literal_ starts with the character sequence `U+0030` `U+006F` (`0o`) and continues as any mixture (with at least one digit) of octal digits and underscores. + +r[lex.token.literal.int.kind-bin] * A _binary literal_ starts with the character sequence `U+0030` `U+0062` (`0b`) and continues as any mixture (with at least one digit) of binary digits and underscores. +r[lex.token.literal.int.restriction] Like any literal, an integer literal may be followed (immediately, without any spaces) by a suffix as described above. The suffix may not begin with `e` or `E`, as that would be interpreted as the exponent of a floating-point literal. See [Integer literal expressions] for the effect of these suffixes. @@ -515,13 +611,18 @@ Examples of integer literals which are not accepted as literal expressions: #### Tuple index +r[lex.token.literal.int.tuple-field] + +r[lex.token.literal.int.tuple-field.syntax] > **Lexer**\ > TUPLE_INDEX: \ >    INTEGER_LITERAL +r[lex.token.literal.int.tuple-field.intro] A tuple index is used to refer to the fields of [tuples], [tuple structs], and [tuple variants]. +r[lex.token.literal.int.tuple-field.eq] Tuple indices are compared with the literal token directly. Tuple indices start with `0` and each successive index increments the value by `1` as a decimal value. Thus, only decimal values will match, and the value must not @@ -541,6 +642,9 @@ let horse = example.0b10; // ERROR no field named `0b10` #### Floating-point literals +r[lex.token.literal.float] + +r[lex.token.literal.float.syntax] > **Lexer**\ > FLOAT_LITERAL :\ >       DEC_LITERAL `.` @@ -553,12 +657,14 @@ let horse = example.0b10; // ERROR no field named `0b10` > (DEC_DIGIT|`_`)\* DEC_DIGIT (DEC_DIGIT|`_`)\* > +r[lex.token.literal.float.form] A _floating-point literal_ has one of two forms: * A _decimal literal_ followed by a period character `U+002E` (`.`). This is optionally followed by another decimal literal, with an optional _exponent_. * A single _decimal literal_ followed by an _exponent_. +r[lex.token.literal.float.suffix] Like integer literals, a floating-point literal may be followed by a suffix, so long as the pre-suffix part does not end with `U+002E` (`.`). The suffix may not begin with `e` or `E` if the literal does not include an exponent. @@ -575,7 +681,7 @@ let x: f64 = 2.; ``` This last example is different because it is not possible to use the suffix -syntax with a floating point literal ending in a period. `2.f64` would attempt +syntax with a floating point literal end.token.ing in a period. `2.f64` would attempt to call a method named `f64` on `2`. Note that `-1.0`, for example, is analyzed as two tokens: `-` followed by `1.0`. @@ -594,6 +700,8 @@ Examples of floating-point literals which are not accepted as literal expression #### Reserved forms similar to number literals +r[lex.token.literal.reserved] + > **Lexer**\ > RESERVED_NUMBER :\ >       BIN_LITERAL \[`2`-`9`​]\ @@ -606,17 +714,23 @@ Examples of floating-point literals which are not accepted as literal expression >    | `0x` `_`\* _end of input or not HEX_DIGIT_\ >    | DEC_LITERAL ( . DEC_LITERAL)? (`e`|`E`) (`+`|`-`)? _end of input or not DEC_DIGIT_ +r[lex.token.literal.reserved.intro] The following lexical forms similar to number literals are _reserved forms_. Due to the possible ambiguity these raise, they are rejected by the tokenizer instead of being interpreted as separate tokens. +r[lex.token.literal.reserved.out-of-range] * An unsuffixed binary or octal literal followed, without intervening whitespace, by a decimal digit out of the range for its radix. +r[lex.token.literal.reserved.period] * An unsuffixed binary, octal, or hexadecimal literal followed, without intervening whitespace, by a period character (with the same restrictions on what follows the period as for floating-point literals). +r[lex.token.literal.reserved.exp] * An unsuffixed binary or octal literal followed, without intervening whitespace, by the character `e` or `E`. +r[lex.token.literal.reserved.empty-with-radix] * Input which begins with one of the radix prefixes but is not a valid binary, octal, or hexadecimal literal (because it contains no digits). +r[lex.token.literal.reserved.empty-exp] * Input which has the form of a floating-point literal with no digits in the exponent. Examples of reserved forms: @@ -636,6 +750,9 @@ Examples of reserved forms: ## Lifetimes and loop labels +r[lex.token.life] + +r[lex.token.life.syntax] > **Lexer**\ > LIFETIME_TOKEN :\ >       `'` [IDENTIFIER_OR_KEYWORD][identifier] @@ -649,12 +766,16 @@ Examples of reserved forms: >    | `'_` > _(not immediately followed by `'`)_ +r[lex.token.life.intro] Lifetime parameters and [loop labels] use LIFETIME_OR_LABEL tokens. Any LIFETIME_TOKEN will be accepted by the lexer, and for example, can be used in macros. ## Punctuation +r[lex.token.punct] + +r[lex.token.punct.intro] Punctuation symbol tokens are listed here for completeness. Their individual usages and meanings are defined in the linked pages. @@ -710,6 +831,8 @@ usages and meanings are defined in the linked pages. ## Delimiters +r[lex.token.delim] + Bracket punctuation is used in various parts of the grammar. An open bracket must always be paired with a close bracket. Brackets and the tokens within them are referred to as "token trees" in [macros]. The three types of brackets are: @@ -722,19 +845,27 @@ them are referred to as "token trees" in [macros]. The three types of brackets ## Reserved prefixes +r[lex.token.reserved-prefix] + +r[lex.token.reserved-prefix.syntax] > **Lexer 2021+**\ > RESERVED_TOKEN_DOUBLE_QUOTE : ( IDENTIFIER_OR_KEYWORD _Except `b` or `c` or `r` or `br` or `cr`_ | `_` ) `"`\ > RESERVED_TOKEN_SINGLE_QUOTE : ( IDENTIFIER_OR_KEYWORD _Except `b`_ | `_` ) `'`\ > RESERVED_TOKEN_POUND : ( IDENTIFIER_OR_KEYWORD _Except `r` or `br` or `cr`_ | `_` ) `#` +r[lex.token.reserved-prefix.intro] Some lexical forms known as _reserved prefixes_ are reserved for future use. +r[lex.token.reserved-prefix.id] Source input which would otherwise be lexically interpreted as a non-raw identifier (or a keyword or `_`) which is immediately followed by a `#`, `'`, or `"` character (without intervening whitespace) is identified as a reserved prefix. +r[lex.token.reserved-prefix.raw-token] Note that raw identifiers, raw string literals, and raw byte string literals may contain a `#` character but are not interpreted as containing a reserved prefix. +r[lex.token.reserved-prefix.strings] Similarly the `r`, `b`, `br`, `c`, and `cr` prefixes used in raw string literals, byte literals, byte string literals, raw byte string literals, C string literals, and raw C string literals are not interpreted as reserved prefixes. +r[lex.token.reserved-prefix.edition2021] > **Edition differences**: Starting with the 2021 edition, reserved prefixes are reported as an error by the lexer (in particular, they cannot be passed to macros). > > Before the 2021 edition, reserved prefixes are accepted by the lexer and interpreted as multiple tokens (for example, one token for the identifier or keyword, followed by a `#` token). diff --git a/src/whitespace.md b/src/whitespace.md index a93bdcb..cd09994 100644 --- a/src/whitespace.md +++ b/src/whitespace.md @@ -1,5 +1,8 @@ # Whitespace +r[lex.whitespace] + +r[lex.whitespace.intro] Whitespace is any non-empty string containing only characters that have the [`Pattern_White_Space`] Unicode property, namely: @@ -15,9 +18,11 @@ Whitespace is any non-empty string containing only characters that have the - `U+2028` (line separator) - `U+2029` (paragraph separator) +r[lex.whitespace.token-sep] Rust is a "free-form" language, meaning that all forms of whitespace serve only to separate _tokens_ in the grammar, and have no semantic significance. +r[lex.whitespace.replacement] A Rust program has identical meaning if each whitespace element is replaced with any other legal whitespace element, such as a single space character. From 52312ae4689698fe18f04ee0521c8706821cc690 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 22 Sep 2024 08:01:50 +0200 Subject: [PATCH 081/189] do not talk about the 'address of a constant' --- src/items/constant-items.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/items/constant-items.md b/src/items/constant-items.md index 9fb2185..f6ba8da 100644 --- a/src/items/constant-items.md +++ b/src/items/constant-items.md @@ -14,13 +14,12 @@ guaranteed to refer to the same memory address. The constant declaration defines the constant value in the [value namespace] of the module or block where it is located. Constants must be explicitly typed. The type must have a `'static` lifetime: any -references in the initializer must have `'static` lifetimes. +references in the initializer must have `'static` lifetimes. References +in the type of a constant default to `'static` lifetime; see [static lifetime +elision]. -Constants may refer to the address of other constants, in which case the -address will have elided lifetimes where applicable, otherwise -- in most cases --- defaulting to the `static` lifetime. (See [static lifetime -elision].) The compiler is, however, still at liberty to translate the constant -many times, so the address referred to may not be stable. +A reference to a constant will have `'static` lifetime if the constant value is eligible for +[promotion]; otherwise, a temporary will be created. ```rust const BIT1: u32 = 1 << 0; @@ -118,3 +117,4 @@ fn unused_generic_function() { [_Expression_]: ../expressions.md [`Copy`]: ../special-types-and-traits.md#copy [value namespace]: ../names/namespaces.md +[promotion]: ../destructors.md#constant-promotion From c9f5df9c05ec9975f261c7c1b41deaac15efcba8 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 10:57:38 -0400 Subject: [PATCH 082/189] Remove restriction and constraint keywords --- docs/authoring.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/authoring.md b/docs/authoring.md index d64fb21..975ab78 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -87,8 +87,6 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo 4. The following keywords should be used to identify paragraphs when unambiguous: * `intro`: The beginning paragraph of each section - should explain the construct being defined overall. * `syntax`: Syntax definitions or explanations when BNF syntax definitions are not used - * `restriction`: Syntactic (parsing) requirements on the construct - * `constraint`: Semantic (type checking) requirements on the construct * `safety` (instead of restriction): Stating that an operation is `unsafe` or the conditions under which it is `unsafe` * `behavior`: Runtime effects of evaluating the construct in a well-defined manner * `panics`: Conditions under which evaluating the construct causes a runtime panic From 7a23c6887bd5b225631f025197ff232084e7a385 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 12:56:47 -0400 Subject: [PATCH 083/189] Add idenfitiers to mbe and proc-macro --- src/macros-by-example.md | 90 ++++++++++++++++++++++++++++++++++++---- src/procedural-macros.md | 46 ++++++++++++++++++++ 2 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index e95cd2e..93320f9 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -1,5 +1,8 @@ # Macros By Example +r[macro.decl] + +r[macro.decl.syntax] > **Syntax**\ > _MacroRulesDefinition_ :\ >    `macro_rules` `!` [IDENTIFIER] _MacroRulesDef_ @@ -39,6 +42,7 @@ > _MacroTranscriber_ :\ >    [_DelimTokenTree_] +r[macro.decl.intro] `macro_rules` allows users to define syntax extension in a declarative way. We call such extensions "macros by example" or simply "macros". @@ -51,10 +55,15 @@ items), types, or patterns. ## Transcribing +r[macro.decl.transcription] + +r[macro.decl.transcription.intro] When a macro is invoked, the macro expander looks up macro invocations by name, and tries each macro rule in turn. It transcribes the first successful match; if -this results in an error, then future matches are not tried. When matching, no -lookahead is performed; if the compiler cannot unambiguously determine how to +this results in an error, then future matches are not tried. + +r[macro.decl.transcription.lookahead] +When matching, no lookahead is performed; if the compiler cannot unambiguously determine how to parse the macro invocation one token at a time, then it is an error. In the following example, the compiler does not look ahead past the identifier to see if the following token is a `)`, even though that would allow it to parse the @@ -68,6 +77,7 @@ macro_rules! ambiguity { ambiguity!(error); // Error: local ambiguity ``` +r[macro.decl.transcription.syntax] In both the matcher and the transcriber, the `$` token is used to invoke special behaviours from the macro engine (described below in [Metavariables] and [Repetitions]). Tokens that aren't part of such an invocation are matched and @@ -78,6 +88,8 @@ instance, the matcher `(())` will match `{()}` but not `{{}}`. The character ### Forwarding a matched fragment +r[macro.decl.transcription.fragment] + When forwarding a matched fragment to another macro-by-example, matchers in the second macro will see an opaque AST of the fragment type. The second macro can't use literal tokens to match the fragments in the matcher, only a @@ -116,9 +128,14 @@ foo!(3); ## Metavariables +r[macro.decl.meta] + +r[macro.decl.meta.intro] In the matcher, `$` _name_ `:` _fragment-specifier_ matches a Rust syntax -fragment of the kind specified and binds it to the metavariable `$`_name_. Valid -fragment specifiers are: +fragment of the kind specified and binds it to the metavariable `$`_name_. + +r[macro.decl.meta.specifier] +Valid fragment specifiers are: * `item`: an [_Item_] * `block`: a [_BlockExpression_] @@ -136,18 +153,23 @@ fragment specifiers are: * `vis`: a possibly empty [_Visibility_] qualifier * `literal`: matches `-`?[_LiteralExpression_] +r[macro.decl.meta.transcription] In the transcriber, metavariables are referred to simply by `$`_name_, since the fragment kind is specified in the matcher. Metavariables are replaced with -the syntax element that matched them. The keyword metavariable `$crate` can be -used to refer to the current crate; see [Hygiene] below. Metavariables can be +the syntax element that matched them. + +r[macro.decl.meta.dollar-crate] +The keyword metavariable `$crate` can be used to refer to the current crate; see [Hygiene] below. Metavariables can be transcribed more than once or not at all. +r[macro.decl.meta.expr-underscore] For reasons of backwards compatibility, though `_` [is also an expression][_UnderscoreExpression_], a standalone underscore is not matched by the `expr` fragment specifier. However, `_` is matched by the `expr` fragment specifier when it appears as a subexpression. For the same reason, a standalone [const block] is not matched but it is matched when appearing as a subexpression. +r[macro.decl.meta.edition2021] > **Edition differences**: Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]). > > Before the 2021 edition, they match exactly the same fragments as `pat_param` (that is, they accept [_PatternNoTopAlt_]). @@ -156,22 +178,31 @@ For the same reason, a standalone [const block] is not matched but it is matched ## Repetitions +r[macro.decl.repetition] + +r[macro.decl.repetition.intro] In both the matcher and transcriber, repetitions are indicated by placing the tokens to be repeated inside `$(`…`)`, followed by a repetition operator, -optionally with a separator token between. The separator token can be any token +optionally with a separator token between. + +r[macro.decl.repetition.separator] +The separator token can be any token other than a delimiter or one of the repetition operators, but `;` and `,` are the most common. For instance, `$( $i:ident ),*` represents any number of identifiers separated by commas. Nested repetitions are permitted. +r[macro.decl.repetition.operators] The repetition operators are: - `*` --- indicates any number of repetitions. - `+` --- indicates any number but at least one. - `?` --- indicates an optional fragment with zero or one occurrence. +r[macro.decl.repetition.optional-restriction] Since `?` represents at most one occurrence, it cannot be used with a separator. +r[macro.decl.repetition.fragment] The repeated fragment both matches and transcribes to the specified number of the fragment, separated by the separator token. Metavariables are matched to every repetition of their corresponding fragment. For instance, the `$( $i:ident @@ -198,6 +229,9 @@ compiler knows how to expand them properly: ## Scoping, Exporting, and Importing +r[macro.decl.scope] + +r[macro.decl.scope.intro] For historical reasons, the scoping of macros by example does not work entirely like items. Macros have two forms of scope: textual scope, and path-based scope. Textual scope is based on the order that things appear in source files, or even @@ -205,6 +239,7 @@ across multiple files, and is the default scoping. It is explained further below Path-based scope works exactly the same way that item scoping does. The scoping, exporting, and importing of macros is controlled largely by attributes. +r[macro.decl.scope.unqualified] When a macro is invoked by an unqualified identifier (not part of a multi-part path), it is first looked up in textual scoping. If this does not yield any results, then it is looked up in path-based scoping. If the macro's name is @@ -224,6 +259,9 @@ self::lazy_static!{} // Path-based lookup ignores our macro, finds imported one. ### Textual Scope +r[macro.decl.scope.textual] + +r[macro.decl.scope.textual.intro] Textual scope is based largely on the order that things appear in source files, and works similarly to the scope of local variables declared with `let` except it also applies at the module level. When `macro_rules!` is used to define a @@ -253,6 +291,7 @@ mod has_macro { m!{} // OK: appears after declaration of m in src/lib.rs ``` +r[macro.decl.scope.textual.shadow] It is not an error to define a macro multiple times; the most recent declaration will shadow the previous one unless it has gone out of scope. @@ -299,6 +338,9 @@ fn foo() { ### The `macro_use` attribute +r[macro.decl.scope.macro_use] + +r[macro.decl.scope.macro_use.mod-decl] The *`macro_use` attribute* has two purposes. First, it can be used to make a module's macro scope not end when the module is closed, by applying it to a module: @@ -314,6 +356,7 @@ mod inner { m!(); ``` +r[macro.decl.scope.macro_use.prelude] Second, it can be used to import macros from another crate, by attaching it to an `extern crate` declaration appearing in the crate's root module. Macros imported this way are imported into the [`macro_use` prelude], not textually, @@ -332,11 +375,15 @@ lazy_static!{} // self::lazy_static!{} // Error: lazy_static is not defined in `self` ``` +r[macro.decl.scope.macro_use.export] Macros to be imported with `#[macro_use]` must be exported with `#[macro_export]`, which is described below. ### Path-Based Scope +r[macro.decl.scope.path] + +r[macro.decl.scope.path.intro] By default, a macro has no path-based scope. However, if it has the `#[macro_export]` attribute, then it is declared in the crate root scope and can be referred to normally as such: @@ -358,11 +405,15 @@ mod mac { } ``` +r[macro.decl.scope.path.export] Macros labeled with `#[macro_export]` are always `pub` and can be referred to by other crates, either by path or by `#[macro_use]` as described above. ## Hygiene +r[macro.decl.hygiene] + +r[macreo.decl.hygiene.intro] By default, all identifiers referred to in a macro are expanded as-is, and are looked up at the macro's invocation site. This can lead to issues if a macro refers to an item or macro which isn't in scope at the invocation site. To @@ -406,6 +457,7 @@ pub mod inner { } ``` +r[macro.decl.hygiene.vis] Additionally, even though `$crate` allows a macro to refer to items within its own crate when expanding, its use has no effect on visibility. An item or macro referred to must still be visible from the invocation site. In the following @@ -429,6 +481,7 @@ fn foo() {} > modified to use `$crate` or `local_inner_macros` to work well with path-based > imports. +r[macro.decl.hygeine.local_inner_macros] When a macro is exported, the `#[macro_export]` attribute can have the `local_inner_macros` keyword added to automatically prefix all contained macro invocations with `$crate::`. This is intended primarily as a tool to migrate @@ -449,9 +502,15 @@ macro_rules! helper { ## Follow-set Ambiguity Restrictions +r[macro.decl.follow-set] + +r[macro.decl.follow-set.intro] The parser used by the macro system is reasonably powerful, but it is limited in -order to prevent ambiguity in current or future versions of the language. In -particular, in addition to the rule about ambiguous expansions, a nonterminal +order to prevent ambiguity in current or future versions of the language. + + +r[macro.decl.follow-set.token-restriction] +In particular, in addition to the rule about ambiguous expansions, a nonterminal matched by a metavariable must be followed by a token which has been decided can be safely used after that kind of match. @@ -464,19 +523,32 @@ matcher would become ambiguous or would misparse, breaking working code. Matchers like `$i:expr,` or `$i:expr;` would be legal, however, because `,` and `;` are legal expression separators. The specific rules are: +r[macro.decl.follow-set.token-expr-stmt] * `expr` and `stmt` may only be followed by one of: `=>`, `,`, or `;`. + +r[macro.decl.follow-set.token-pat_param] * `pat_param` may only be followed by one of: `=>`, `,`, `=`, `|`, `if`, or `in`. + +r[macro.decl.follow-set.token-pat] * `pat` may only be followed by one of: `=>`, `,`, `=`, `if`, or `in`. + +r[macro.decl.follow-set.token-path-ty] * `path` and `ty` may only be followed by one of: `=>`, `,`, `=`, `|`, `;`, `:`, `>`, `>>`, `[`, `{`, `as`, `where`, or a macro variable of `block` fragment specifier. + +r[macro.decl.follow-set.token-vis] * `vis` may only be followed by one of: `,`, an identifier other than a non-raw `priv`, any token that can begin a type, or a metavariable with a `ident`, `ty`, or `path` fragment specifier. + +r[macro.decl.follow-set.token-other] * All other fragment specifiers have no restrictions. +r[macro.decl.follow-set.edition2021] > **Edition differences**: Before the 2021 edition, `pat` may also be followed by `|`. +r[macro.decl.follow-set.repetition] When repetitions are involved, then the rules apply to every possible number of expansions, taking separators into account. This means: diff --git a/src/procedural-macros.md b/src/procedural-macros.md index a97755f..0421fc7 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -1,5 +1,8 @@ ## Procedural Macros +r[macro.proc] + +r[macro.proc.intro] *Procedural macros* allow creating syntax extensions as execution of a function. Procedural macros come in one of three flavors: @@ -11,6 +14,7 @@ Procedural macros allow you to run code at compile time that operates over Rust syntax, both consuming and producing Rust syntax. You can sort of think of procedural macros as functions from an AST to another AST. +r[macro.proc.def] Procedural macros must be defined in the root of a crate with the [crate type] of `proc-macro`. The macros may not be used from the crate where they are defined, and can only be used when imported in another crate. @@ -23,6 +27,7 @@ The macros may not be used from the crate where they are defined, and can only b > proc-macro = true > ``` +r[macro.proc.result] As functions, they must either return syntax, panic, or loop endlessly. Returned syntax either replaces or adds the syntax depending on the kind of procedural macro. Panics are caught by the compiler and are turned into a compiler error. @@ -34,15 +39,20 @@ that the compiler has access to. Similarly, file access is the same. Because of this, procedural macros have the same security concerns that [Cargo's build scripts] have. +r[macro.proc.error] Procedural macros have two ways of reporting errors. The first is to panic. The second is to emit a [`compile_error`] macro invocation. ### The `proc_macro` crate +r[macro.proc.proc_macro] + +r[macro.proc.proc_macro.intro] Procedural macro crates almost always will link to the compiler-provided [`proc_macro` crate]. The `proc_macro` crate provides types required for writing procedural macros and facilities to make it easier. +r[macro.proc.proc_macro.token-stream] This crate primarily contains a [`TokenStream`] type. Procedural macros operate over *token streams* instead of AST nodes, which is a far more stable interface over time for both the compiler and for procedural macros to target. A @@ -51,6 +61,7 @@ can roughly be thought of as lexical token. For example `foo` is an `Ident` token, `.` is a `Punct` token, and `1.2` is a `Literal` token. The `TokenStream` type, unlike `Vec`, is cheap to clone. +r[macro.proc.proc_macro.span] All tokens have an associated `Span`. A `Span` is an opaque value that cannot be modified but can be manufactured. `Span`s represent an extent of source code within a program and are primarily used for error reporting. While you @@ -59,6 +70,8 @@ with any token, such as through getting a `Span` from another token. ### Procedural macro hygiene +r[macro.proc.hygiene] + Procedural macros are *unhygienic*. This means they behave as if the output token stream was simply written inline to the code it's next to. This means that it's affected by external items and also affects external imports. @@ -71,13 +84,19 @@ other functions (like `__internal_foo` instead of `foo`). ### Function-like procedural macros +r[macro.proc.function] + +r[macro.proc.function.intro] *Function-like procedural macros* are procedural macros that are invoked using the macro invocation operator (`!`). +r[macro.proc.function.def] These macros are defined by a [public] [function] with the `proc_macro` [attribute] and a signature of `(TokenStream) -> TokenStream`. The input [`TokenStream`] is what is inside the delimiters of the macro invocation and the output [`TokenStream`] replaces the entire macro invocation. + +r[macro.proc.function.namespace] The `proc_macro` attribute defines the macro in the [macro namespace] in the root of the crate. For example, the following macro definition ignores its input and outputs a @@ -109,6 +128,7 @@ fn main() { } ``` +r[macro.proc.function.invocation] Function-like procedural macros may be invoked in any macro invocation position, which includes [statements], [expressions], [patterns], [type expressions], [item] positions, including items in [`extern` blocks], inherent @@ -116,14 +136,21 @@ and trait [implementations], and [trait definitions]. ### Derive macros +r[macro.proc.derive] + +r[macro.proc.derive.intro] *Derive macros* define new inputs for the [`derive` attribute]. These macros can create new [items] given the token stream of a [struct], [enum], or [union]. They can also define [derive macro helper attributes]. +r[macro.proc.derive.def] Custom derive macros are defined by a [public] [function] with the `proc_macro_derive` attribute and a signature of `(TokenStream) -> TokenStream`. + +r[macro.proc.derive.namespace] The `proc_macro_derive` attribute defines the custom derive in the [macro namespace] in the root of the crate. +r[macro.proc.derive.output] The input [`TokenStream`] is the token stream of the item that has the `derive` attribute on it. The output [`TokenStream`] must be a set of items that are then appended to the [module] or [block] that the item from the input @@ -161,11 +188,15 @@ fn main() { #### Derive macro helper attributes +r[macro.proc.derive.attributes] + +r[macro.proc.derive.attributes.intro] Derive macros can add additional [attributes] into the scope of the [item] they are on. Said attributes are called *derive macro helper attributes*. These attributes are [inert], and their only purpose is to be fed into the derive macro that defined them. That said, they can be seen by all macros. +r[macro.proc.derive.attributes.def] The way to define helper attributes is to put an `attributes` key in the `proc_macro_derive` macro with a comma separated list of identifiers that are the names of the helper attributes. @@ -197,10 +228,14 @@ struct Struct { ### Attribute macros +r[macro.proc.attribute] + +r[macro.proc.attribute.intro] *Attribute macros* define new [outer attributes][attributes] which can be attached to [items], including items in [`extern` blocks], inherent and trait [implementations], and [trait definitions]. +r[macro.proc.attribute.def] Attribute macros are defined by a [public] [function] with the `proc_macro_attribute` [attribute] that has a signature of `(TokenStream, TokenStream) -> TokenStream`. The first [`TokenStream`] is the delimited token @@ -209,6 +244,8 @@ the attribute is written as a bare attribute name, the attribute [`TokenStream`] is empty. The second [`TokenStream`] is the rest of the [item] including other [attributes] on the [item]. The returned [`TokenStream`] replaces the [item] with an arbitrary number of [items]. + +r[macro.proc.attribute.namespace] The `proc_macro_attribute` attribute defines the attribute in the [macro namespace] in the root of the crate. For example, this attribute macro takes the input stream and returns it as is, @@ -278,9 +315,13 @@ fn invoke4() {} ### Declarative macro tokens and procedural macro tokens +r[macro.proc.token] + +r[macro.proc.token.intro] Declarative `macro_rules` macros and procedural macros use similar, but different definitions for tokens (or rather [`TokenTree`s].) +r[macro.proc.token.macro_rules] Token trees in `macro_rules` (corresponding to `tt` matchers) are defined as - Delimited groups (`(...)`, `{...}`, etc) - All operators supported by the language, both single-character and @@ -296,6 +337,7 @@ Token trees in `macro_rules` (corresponding to `tt` matchers) are defined as expansion, which will be considered a single token tree regardless of the passed expression) +r[macro.proc.token.tree] Token trees in procedural macros are defined as - Delimited groups (`(...)`, `{...}`, etc) - All punctuation characters used in operators supported by the language (`+`, @@ -306,11 +348,13 @@ Token trees in procedural macros are defined as and floating point literals. - Identifiers, including keywords (`ident`, `r#ident`, `fn`) +r[macro.proc.token.converstion-intro] Mismatches between these two definitions are accounted for when token streams are passed to and from procedural macros. \ Note that the conversions below may happen lazily, so they might not happen if the tokens are not actually inspected. +r[macro.proc.token.conversion] When passed to a proc-macro - All multi-character operators are broken into single characters. - Lifetimes are broken into a `'` character and an identifier. @@ -322,6 +366,7 @@ When passed to a proc-macro - `tt` and `ident` substitutions are never wrapped into such groups and always represented as their underlying token trees. +r[macro.proc.token.emission] When emitted from a proc macro - Punctuation characters are glued into multi-character operators when applicable. @@ -330,6 +375,7 @@ When emitted from a proc macro possibly wrapped into a delimited group ([`Group`]) with implicit delimiters ([`Delimiter::None`]) when it's necessary for preserving parsing priorities. +r[macro.proc.token.doc-comment] Note that neither declarative nor procedural macros support doc comment tokens (e.g. `/// Doc`), so they are always converted to token streams representing their equivalent `#[doc = r"str"]` attributes when passed to macros. From c4780c10b2508871567a49ab95cecdac8821a76f Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 12:57:20 -0400 Subject: [PATCH 084/189] Remove double line breaks --- src/macros-by-example.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 93320f9..6009eed 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -332,7 +332,6 @@ fn foo() { m!(); } - // m!(); // Error: m is not in scope. ``` @@ -508,7 +507,6 @@ r[macro.decl.follow-set.intro] The parser used by the macro system is reasonably powerful, but it is limited in order to prevent ambiguity in current or future versions of the language. - r[macro.decl.follow-set.token-restriction] In particular, in addition to the rule about ambiguous expansions, a nonterminal matched by a metavariable must be followed by a token which has been decided can @@ -562,7 +560,6 @@ expansions, taking separators into account. This means: * If the repetition can match zero times (`*` or `?`), then whatever comes after must be able to follow whatever comes before. - For more detail, see the [formal specification]. [const block]: expressions/block-expr.md#const-blocks From 2cb85280346e67ba1a7c6e3f27837930fa1150a1 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 13:05:37 -0400 Subject: [PATCH 085/189] Add identifiers to variables.md --- src/variables.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/variables.md b/src/variables.md index 5e5ec1b..0e22af6 100644 --- a/src/variables.md +++ b/src/variables.md @@ -1,20 +1,27 @@ # Variables +r[variable] + +r[variable.intro] A _variable_ is a component of a stack frame, either a named function parameter, an anonymous [temporary](expressions.md#temporaries), or a named local variable. +r[variable.local] A _local variable_ (or *stack-local* allocation) holds a value directly, allocated within the stack's memory. The value is a part of the stack frame. +r[variable.local-mut] Local variables are immutable unless declared otherwise. For example: `let mut x = ...`. +r[variable.param-mut] Function parameters are immutable unless declared with `mut`. The `mut` keyword applies only to the following parameter. For example: `|mut x, y|` and `fn f(mut x: Box, y: Box)` declare one mutable variable `x` and one immutable variable `y`. +r[variable.init] Local variables are not initialized when allocated. Instead, the entire frame worth of local variables are allocated, on frame-entry, in an uninitialized state. Subsequent statements within a function may or may not initialize the From ff682b482ed852b384b74b723b915d023ed6d970 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 13:12:32 -0400 Subject: [PATCH 086/189] Add identifier syntax to visibility-and-privacy.md --- src/visibility-and-privacy.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/visibility-and-privacy.md b/src/visibility-and-privacy.md index 5ccf8b4..a38c36c 100644 --- a/src/visibility-and-privacy.md +++ b/src/visibility-and-privacy.md @@ -1,5 +1,8 @@ # Visibility and Privacy +r[vis] + +r[vis.syntax] > **Syntax**\ > _Visibility_ :\ >       `pub`\ @@ -8,20 +11,24 @@ >    | `pub` `(` `super` `)`\ >    | `pub` `(` `in` [_SimplePath_] `)` +r[vis.intro] These two terms are often used interchangeably, and what they are attempting to convey is the answer to the question "Can this item be used at this location?" +r[vis.name-hierarchy] Rust's name resolution operates on a global hierarchy of namespaces. Each level in the hierarchy can be thought of as some item. The items are one of those mentioned above, but also include external crates. Declaring or defining a new module can be thought of as inserting a new tree into the hierarchy at the location of the definition. +r[vis.privacy] To control whether interfaces can be used across modules, Rust checks each use of an item to see whether it should be allowed or not. This is where privacy warnings are generated, or otherwise "you used a private item of another module and weren't allowed to." +r[vis.default] By default, everything is *private*, with two exceptions: Associated items in a `pub` Trait are public by default; Enum variants in a `pub` enum are also public by default. When an item is declared as `pub`, @@ -44,6 +51,7 @@ pub enum State { } ``` +r[vis.access] With the notion of an item being either public or private, Rust allows item accesses in two cases: @@ -78,8 +86,10 @@ explain, here's a few use cases and what they would entail: In the second case, it mentions that a private item "can be accessed" by the current module and its descendants, but the exact meaning of accessing an item -depends on what the item is. Accessing a module, for example, would mean -looking inside of it (to import more items). On the other hand, accessing a +depends on what the item is. + +r[vis.usage] +Accessing a module, for example, would mean looking inside of it (to import more items). On the other hand, accessing a function would mean that it is invoked. Additionally, path expressions and import statements are considered to access an item in the sense that the import/expression is only valid if the destination is in the current visibility @@ -144,18 +154,30 @@ expressions, types, etc. ## `pub(in path)`, `pub(crate)`, `pub(super)`, and `pub(self)` +r[vis.scoped] + +r[vis.scoped.intro] In addition to public and private, Rust allows users to declare an item as visible only within a given scope. The rules for `pub` restrictions are as follows: + +r[vis.scoped.in] - `pub(in path)` makes an item visible within the provided `path`. `path` must be a simple path which resolves to an ancestor module of the item whose visibility is being declared. Each identifier in `path` must refer directly to a module (not to a name introduced by a `use` statement). + +r[vis.scoped.crate] - `pub(crate)` makes an item visible within the current crate. + +r[vis.scoped.super] - `pub(super)` makes an item visible to the parent module. This is equivalent to `pub(in super)`. + +r[vis.scoped.self] - `pub(self)` makes an item visible to the current module. This is equivalent to `pub(in self)` or not using `pub` at all. +r[vis.scoped.edition2018] > **Edition differences**: Starting with the 2018 edition, paths for > `pub(in path)` must start with `crate`, `self`, or `super`. The 2015 edition > may also use paths starting with `::` or modules from the crate root. @@ -219,6 +241,9 @@ fn main() { bar() } ## Re-exporting and Visibility +r[vis.export] + +r[vis.export.intro] Rust allows publicly re-exporting items through a `pub use` directive. Because this is a public directive, this allows the item to be used in the current module through the rules above. It essentially allows public access into the @@ -239,6 +264,7 @@ mod implementation { This means that any external crate referencing `implementation::api::f` would receive a privacy violation, while the path `api::f` would be allowed. +r[vis.export.priv] When re-exporting a private item, it can be thought of as allowing the "privacy chain" being short-circuited through the reexport instead of passing through the namespace hierarchy as it normally would. From cb027f8e1554566d9b7516c30ebe4a2f6e758e69 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 13:14:46 -0400 Subject: [PATCH 087/189] Fix identifier duplication `lex.token.literal.str-raw.content` --- src/tokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tokens.md b/src/tokens.md index ef914a1..774a73b 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -357,7 +357,7 @@ The _raw string body_ can contain any sequence of ASCII characters other than `U It is terminated only by another `U+0022` (double-quote) character, followed by the same number of `U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote) character. A raw byte string literal can not contain any non-ASCII byte. -r[lex.token.literal.str-raw.content] +r[lex.token.literal.str-byte-raw.content] All characters contained in the raw string body represent their ASCII encoding, the characters `U+0022` (double-quote) (except when followed by at least as many `U+0023` (`#`) characters as were used to start the raw string literal) or From 9f43b7f85377ede7992ce111c806a498ad92a3cb Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 13:16:14 -0400 Subject: [PATCH 088/189] Hecking trailing space --- src/types/closure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/closure.md b/src/types/closure.md index 7768ceb..0f59f3f 100644 --- a/src/types/closure.md +++ b/src/types/closure.md @@ -65,7 +65,7 @@ types, by copy, regardless of whether a borrow would work. The `move` keyword is usually used to allow the closure to outlive the captured values, such as if the closure is being returned or used to spawn a new thread. -r[type.closure.capture.composite] +r[type.closure.capture.composite] Composite types such as structs, tuples, and enums are always captured entirely, not by individual fields. It may be necessary to borrow into a local variable in order to capture a single field: From 46a3ae69b2d8ec04bba0320cff648b350ad43cd1 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 23 Sep 2024 13:17:10 -0400 Subject: [PATCH 089/189] Add newline to lexical-structure.md --- src/lexical-structure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lexical-structure.md b/src/lexical-structure.md index ac64c78..d70e97a 100644 --- a/src/lexical-structure.md +++ b/src/lexical-structure.md @@ -1,3 +1,3 @@ # Lexical structure - \ No newline at end of file + From 9afc995c3e28e7adc6cc7180724ce938e7223479 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 13 Aug 2024 14:51:02 -0400 Subject: [PATCH 090/189] Add spec identifiers to crates-and-source-files.md --- src/crates-and-source-files.md | 36 ++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index 426ee26..40538f0 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -1,5 +1,8 @@ # Crates and source files +r[crate] + +r[crate.syntax] > **Syntax**\ > _Crate_ :\ >    [_InnerAttribute_]\*\ @@ -10,17 +13,20 @@ > compiler, and the language has always been designed to be compiled. For these > reasons, this section assumes a compiler. +r[crate.compile-time] Rust's semantics obey a *phase distinction* between compile-time and run-time.[^phase-distinction] Semantic rules that have a *static interpretation* govern the success or failure of compilation, while semantic rules that have a *dynamic interpretation* govern the behavior of the program at run-time. +r[crate.unit] The compilation model centers on artifacts called _crates_. Each compilation processes a single crate in source form, and if successful, produces a single crate in binary form: either an executable or some sort of library.[^cratesourcefile] +r[crate.module] A _crate_ is a unit of compilation and linking, as well as versioning, distribution, and runtime loading. A crate contains a _tree_ of nested [module] scopes. The top level of this tree is a module that is @@ -28,22 +34,31 @@ anonymous (from the point of view of paths within the module) and any item within a crate has a canonical [module path] denoting its location within the crate's module tree. +r[crate.input-source] The Rust compiler is always invoked with a single source file as input, and always produces a single output crate. The processing of that source file may result in other source files being loaded as modules. Source files have the extension `.rs`. +r[crate.module-def] A Rust source file describes a module, the name and location of which — in the module tree of the current crate — are defined from outside the source file: either by an explicit [_Module_][module] item in a referencing -source file, or by the name of the crate itself. Every source file is a +source file, or by the name of the crate itself. + +r[crate.inline-module] +Every source file is a module, but not every module needs its own source file: [module definitions][module] can be nested within one file. +r[crate.items] Each source file contains a sequence of zero or more [_Item_] definitions, and may optionally begin with any number of [attributes] that apply to the containing module, most of which influence the behavior of -the compiler. The anonymous crate module can have additional attributes that +the compiler. + +r[crate.attributes] +The anonymous crate module can have additional attributes that apply to the crate as a whole. > **Note**: The file's contents may be preceded by a [shebang]. @@ -62,8 +77,13 @@ apply to the crate as a whole. ## Main Functions -A crate that contains a `main` [function] can be compiled to an executable. If a -`main` function is present, it must take no arguments, must not declare any +r[crate.main] + +r[crate.main.general] +A crate that contains a `main` [function] can be compiled to an executable. + +r[crate.main.restriction] +If a `main` function is present, it must take no arguments, must not declare any [trait or lifetime bounds], must not have any [where clauses], and its return type must implement the [`Termination`] trait. @@ -81,6 +101,7 @@ fn main() -> impl std::process::Termination { } ``` +r[crate.main.import] The `main` function may be an import, e.g. from an external crate or from the current one. ```rust @@ -105,12 +126,18 @@ use foo::bar as main; ### The `no_main` attribute +r[crate.no_main] + The *`no_main` [attribute]* may be applied at the crate level to disable emitting the `main` symbol for an executable binary. This is useful when some other object being linked to defines `main`. ## The `crate_name` attribute +r[crate.crate_name] + + +r[crate.crate_name.general] The *`crate_name` [attribute]* may be applied at the crate level to specify the name of the crate with the [_MetaNameValueStr_] syntax. @@ -118,6 +145,7 @@ name of the crate with the [_MetaNameValueStr_] syntax. #![crate_name = "mycrate"] ``` +r[crate.crate_name.restriction] The crate name must not be empty, and must only contain [Unicode alphanumeric] or `_` (U+005F) characters. From db11046f8ae184042c91143251203177a2049082 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 13 Aug 2024 15:05:25 -0400 Subject: [PATCH 091/189] Fix formatting of crates-and-source-files.md --- src/crates-and-source-files.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index 40538f0..89a04bd 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -44,7 +44,7 @@ r[crate.module-def] A Rust source file describes a module, the name and location of which — in the module tree of the current crate — are defined from outside the source file: either by an explicit [_Module_][module] item in a referencing -source file, or by the name of the crate itself. +source file, or by the name of the crate itself. r[crate.inline-module] Every source file is a @@ -55,7 +55,7 @@ r[crate.items] Each source file contains a sequence of zero or more [_Item_] definitions, and may optionally begin with any number of [attributes] that apply to the containing module, most of which influence the behavior of -the compiler. +the compiler. r[crate.attributes] The anonymous crate module can have additional attributes that @@ -80,7 +80,7 @@ apply to the crate as a whole. r[crate.main] r[crate.main.general] -A crate that contains a `main` [function] can be compiled to an executable. +A crate that contains a `main` [function] can be compiled to an executable. r[crate.main.restriction] If a `main` function is present, it must take no arguments, must not declare any From 227e44ab45f2844593c8d5c929389719a9c99122 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 19:49:28 -0400 Subject: [PATCH 092/189] Remove double line break from crates-and-source-files.md --- src/crates-and-source-files.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index 89a04bd..734ee3e 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -136,7 +136,6 @@ other object being linked to defines `main`. r[crate.crate_name] - r[crate.crate_name.general] The *`crate_name` [attribute]* may be applied at the crate level to specify the name of the crate with the [_MetaNameValueStr_] syntax. From 217b4f02043871dd1fe9b41c4a6b2bec1d6d4edd Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 24 Sep 2024 15:02:54 -0700 Subject: [PATCH 093/189] Tweak rule names In discussion with TC, we felt that these names were more descriptive of the sections they are in. --- src/visibility-and-privacy.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/visibility-and-privacy.md b/src/visibility-and-privacy.md index a38c36c..58e4b96 100644 --- a/src/visibility-and-privacy.md +++ b/src/visibility-and-privacy.md @@ -241,9 +241,9 @@ fn main() { bar() } ## Re-exporting and Visibility -r[vis.export] +r[vis.reexports] -r[vis.export.intro] +r[vis.reexports.intro] Rust allows publicly re-exporting items through a `pub use` directive. Because this is a public directive, this allows the item to be used in the current module through the rules above. It essentially allows public access into the @@ -264,7 +264,7 @@ mod implementation { This means that any external crate referencing `implementation::api::f` would receive a privacy violation, while the path `api::f` would be allowed. -r[vis.export.priv] +r[vis.reexports.private-item] When re-exporting a private item, it can be thought of as allowing the "privacy chain" being short-circuited through the reexport instead of passing through the namespace hierarchy as it normally would. From 560be62646e7924466d6323b1a9be4eb87204b5d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 24 Sep 2024 22:23:30 +0000 Subject: [PATCH 094/189] Add review changes --- src/comments.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/comments.md b/src/comments.md index 9b7b6cd..fa72aba 100644 --- a/src/comments.md +++ b/src/comments.md @@ -1,6 +1,6 @@ # Comments -r[comments.lexical] +r[comments.syntax] > **Lexer**\ > LINE_COMMENT :\ @@ -53,7 +53,7 @@ Line doc comments beginning with exactly _three_ slashes (`///`), and block doc comments (`/** ... */`), both outer doc comments, are interpreted as a special syntax for [`doc` attributes]. -r[comments.doc.attribute] +r[comments.doc.attributes] That is, they are equivalent to writing `#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into `#[doc="Foo"]` and `/** Bar */` turns into `#[doc="Bar"]`. @@ -63,12 +63,12 @@ Line comments beginning with `//!` and block comments `/*! ... */` are doc comments that apply to the parent of the comment, rather than the item that follows. -r[comments.doc.inner-attribute] +r[comments.doc.inner-attributes] That is, they are equivalent to writing `#![doc="..."]` around the body of the comment. `//!` comments are usually used to document modules that occupy a source file. -r[comments.doc.bare-cr] +r[comments.doc.bare-crs] The character `U+000D` (CR) is not allowed in doc comments. > **Note**: The sequence `U+000D` (CR) immediately followed by `U+000A` (LF) would have been previously transformed into a single `U+000A` (LF). From 435eec55e40acac8ba7cf22e26d59a7dd1ed0e51 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 24 Sep 2024 15:24:43 -0700 Subject: [PATCH 095/189] Authoring guide: clarify standard library linking --- docs/authoring.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/authoring.md b/docs/authoring.md index 74c9bc9..b465630 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -15,7 +15,8 @@ This document serves as a guide for editors and reviewers. Some conventions and * Code blocks should have an explicit language tag. * Do not wrap long lines. This helps with reviewing diffs of the source. * Use [smart punctuation] instead of Unicode characters. For example, use `---` for em-dash instead of the Unicode character. Characters like em-dash can be difficult to see in a fixed-width editor, and some editors may not have easy methods to enter such characters. -* Links should be relative with the `.md` extension. Links to other rust-lang books that are published with the reference or the standard library API should also be relative so that the linkchecker can validate them. +* Links should be relative with the `.md` extension. Links to other rust-lang books that are published with the reference should also be relative so that the linkchecker can validate them. +* Links to the standard library should use rustdoc-style links described in [Standard library links](#standard-library-links). * The use of reference links is preferred, with shortcuts if appropriate. Place the sorted link reference definitions at the bottom of the file, or at the bottom of a section if there are an unusually large number of links that are specific to the section. ```markdown From 46a1b9b45ef4375924b5ed89ed57745e40edb19a Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 09:24:14 -0400 Subject: [PATCH 096/189] Add identifier syntax to trait-bounds.md --- src/trait-bounds.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 019a2f7..530e978 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -1,5 +1,8 @@ # Trait and lifetime bounds +r[bound] + +r[bound.syntax] > **Syntax**\ > _TypeParamBounds_ :\ >    _TypeParamBound_ ( `+` _TypeParamBound_ )\* `+`? @@ -35,6 +38,7 @@ >    | [IDENTIFIER][] \ >    | `Self` +r[bound.intro] [Trait] and lifetime bounds provide a way for [generic items][generic] to restrict which types and lifetimes are used as their parameters. Bounds can be provided on any type in a [where clause]. There are also shorter forms for @@ -48,6 +52,7 @@ certain common cases: `trait A { type B: Copy; }` is equivalent to `trait A where Self::B: Copy { type B; }`. +r[bound.satisfication] Bounds on an item must be satisfied when using the item. When type checking and borrow checking a generic item, the bounds can be used to determine that a trait is implemented for a type. For example, given `Ty: Trait` @@ -87,9 +92,11 @@ fn name_figure( } ``` +r[bound.trivial] Bounds that don't use the item's parameters or [higher-ranked lifetimes] are checked when the item is defined. It is an error for such a bound to be false. +r[bound.special] [`Copy`], [`Clone`], and [`Sized`] bounds are also checked for certain generic types when using the item, even if the use does not provide a concrete type. It is an error to have `Copy` or `Clone` as a bound on a mutable reference, [trait object], or [slice]. It is an error to have `Sized` as a bound on a trait object or slice. @@ -107,16 +114,24 @@ where struct UsesA<'a, T>(A<'a, T>); ``` +r[bound.trait-object] Trait and lifetime bounds are also used to name [trait objects]. ## `?Sized` +r[bound.sized] + `?` is only used to relax the implicit [`Sized`] trait bound for [type parameters] or [associated types]. `?Sized` may not be used as a bound for other types. ## Lifetime bounds +r[bound.lifetime] + +r[bound.lifetime.intro] Lifetime bounds can be applied to types or to other lifetimes. + +r[bound.lifetime.outlive-lifetime] The bound `'a: 'b` is usually read as `'a` *outlives* `'b`. `'a: 'b` means that `'a` lasts at least as long as `'b`, so a reference `&'a ()` is valid whenever `&'b ()` is valid. @@ -127,14 +142,19 @@ fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) where 'a: 'b { } ``` +r[bound.lifetime.outlive-type] `T: 'a` means that all lifetime parameters of `T` outlive `'a`. For example, if `'a` is an unconstrained lifetime parameter, then `i32: 'static` and `&'static str: 'a` are satisfied, but `Vec<&'a ()>: 'static` is not. ## Higher-ranked trait bounds +r[bound.higher-ranked] + +r[bound.higher-ranked.syntax] > _ForLifetimes_ :\ >    `for` [_GenericParams_] +r[bound.higher-ranked.intro] Trait bounds may be *higher ranked* over lifetimes. These bounds specify a bound that is true *for all* lifetimes. For example, a bound such as `for<'a> &'a T: PartialEq` would require an implementation like @@ -158,6 +178,7 @@ fn call_on_ref_zero(f: F) where for<'a> F: Fn(&'a i32) { } ``` +r[bound.higher-ranked.trait] Higher-ranked lifetimes may also be specified just before the trait: the only difference is the [scope][hrtb-scopes] of the lifetime parameter, which extends only to the end of the following trait instead of the whole bound. This function is @@ -172,15 +193,20 @@ fn call_on_ref_zero(f: F) where F: for<'a> Fn(&'a i32) { ## Implied bounds +r[bound.implied] + +r[bound.implied.intro] Lifetime bounds required for types to be well-formed are sometimes inferred. ```rust fn requires_t_outlives_a<'a, T>(x: &'a T) {} ``` + The type parameter `T` is required to outlive `'a` for the type `&'a T` to be well-formed. This is inferred because the function signature contains the type `&'a T` which is only valid if `T: 'a` holds. +r[bound.implied.context] Implied bounds are added for all parameters and outputs of functions. Inside of `requires_t_outlives_a` you can assume `T: 'a` to hold even if you don't explicitly specify this: @@ -203,6 +229,7 @@ fn not_implied<'a, T>() { } ``` +r[bound.implied.trait] Only lifetime bounds are implied, trait bounds still have to be explicitly added. The following example therefore causes an error: @@ -213,6 +240,7 @@ struct IsDebug(T); fn doesnt_specify_t_debug(x: IsDebug) {} ``` +r[bound.implied.def] Lifetime bounds are also inferred for type definitions and impl blocks for any type: ```rust @@ -244,6 +272,8 @@ impl<'a, T> Trait<'a, T> for &'a T {} ## Use bounds +r[bound.use] + Certain bounds lists may include a `use<..>` bound to control which generic parameters are captured by the `impl Trait` [abstract return type]. See [precise capturing] for more details. [IDENTIFIER]: identifiers.html From 641cf74c6d39ed10cfe6d6c77020130c7ae0434d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 09:44:35 -0400 Subject: [PATCH 097/189] Add identifier syntax to type-coercions.md --- src/type-coercions.md | 55 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/type-coercions.md b/src/type-coercions.md index 7d254f4..5981170 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -1,9 +1,13 @@ # Type coercions +r[coerce] + +r[coerce.intro] **Type coercions** are implicit operations that change the type of a value. They happen automatically at specific locations and are highly restricted in what types actually coerce. +r[cerce.as] Any conversions allowed by coercion can also be explicitly performed by the [type cast operator], `as`. @@ -11,11 +15,15 @@ Coercions are originally defined in [RFC 401] and expanded upon in [RFC 1558]. ## Coercion sites +r[coerce.site] + +r[coerce.site.intro] A coercion can only occur at certain coercion sites in a program; these are typically places where the desired type is explicit or can be derived by propagation from explicit types (without type inference). Possible coercion sites are: +r[coerce.site.let] * `let` statements where an explicit type is given. For example, `&mut 42` is coerced to have type `&i8` in the following: @@ -24,8 +32,10 @@ sites are: let _: &i8 = &mut 42; ``` +r[coerce.site.value] * `static` and `const` item declarations (similar to `let` statements). +r[coerce.site.argument] * Arguments for function calls The value being coerced is the actual parameter, and it is coerced to @@ -44,6 +54,7 @@ sites are: For method calls, the receiver (`self` parameter) type is coerced differently, see the documentation on [method-call expressions] for details. +r[coerce.site.constructor] * Instantiations of struct, union, or enum variant fields For example, `&mut 42` is coerced to have type `&i8` in the following: @@ -56,6 +67,7 @@ sites are: } ``` +r[coerce.site.return] * Function results—either the final line of a block if it is not semicolon-terminated or any expression in a `return` statement @@ -68,24 +80,30 @@ sites are: } ``` +r[coerce.site.subexpr] If the expression in one of these coercion sites is a coercion-propagating expression, then the relevant sub-expressions in that expression are also coercion sites. Propagation recurses from these new coercion sites. Propagating expressions and their relevant sub-expressions are: +r[coerce.site.array] * Array literals, where the array has type `[U; n]`. Each sub-expression in the array literal is a coercion site for coercion to type `U`. +r[coerce.site.repeat] * Array literals with repeating syntax, where the array has type `[U; n]`. The repeated sub-expression is a coercion site for coercion to type `U`. +r[coerce.site.tuple] * Tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`. Each sub-expression is a coercion site to the respective type, e.g. the zeroth sub-expression is a coercion site to type `U_0`. +r[coerce.site.parenthesis] * Parenthesized sub-expressions (`(e)`): if the expression has type `U`, then the sub-expression is a coercion site to `U`. +r[coerce.site.block] * Blocks: if a block has type `U`, then the last expression in the block (if it is not semicolon-terminated) is a coercion site to `U`. This includes blocks which are part of control flow statements, such as `if`/`else`, if @@ -93,23 +111,33 @@ the block has a known type. ## Coercion types +r[coerce.types] + +r[coerce.types.intro] Coercion is allowed between the following types: +r[coerce.types.reflexive] * `T` to `U` if `T` is a [subtype] of `U` (*reflexive case*) +r[coerce.types.transitive] * `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` (*transitive case*) Note that this is not fully supported yet. +r[coerce.types.mut-reborrow] * `&mut T` to `&T` +r[coerce.types.mut-pointer] * `*mut T` to `*const T` +r[coerce.types.ref-to-pointer] * `&T` to `*const T` +r[coerce.types.mut-to-pointer] * `&mut T` to `*mut T` +r[coerce.types.deref] * `&T` or `&mut T` to `&U` if `T` implements `Deref`. For example: ```rust @@ -135,8 +163,10 @@ Coercion is allowed between the following types: } ``` +r[coerce.types.deref-mut] * `&mut T` to `&mut U` if `T` implements `DerefMut`. +r[coerce.types.unsize] * TyCtor(`T`) to TyCtor(`U`), where TyCtor(`T`) is one of - `&T` - `&mut T` @@ -150,28 +180,38 @@ Coercion is allowed between the following types: structs. In addition, coercions from subtraits to supertraits will be added. See [RFC 401] for more details.--> +r[coerce.types.fn] * Function item types to `fn` pointers +r[coerce.types.closure] * Non capturing closures to `fn` pointers +r[coerce.types.never] * `!` to any `T` ### Unsized Coercions +r[coerce.unsize] + +r[coerce.unsize.intro] The following coercions are called `unsized coercions`, since they relate to converting sized types to unsized types, and are permitted in a few cases where other coercions are not, as described above. They can still happen anywhere else a coercion can occur. +r[coerce.unsize.trait] Two traits, [`Unsize`] and [`CoerceUnsized`], are used to assist in this process and expose it for library use. The following coercions are built-ins and, if `T` can be coerced to `U` with one of them, then an implementation of `Unsize` for `T` will be provided: +r[coerce.unsize.slice] * `[T; n]` to `[T]`. +r[coerce.unsize.trait-object] * `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [object safe]. +r[coerce.unsized.composite] * `Foo<..., T, ...>` to `Foo<..., U, ...>`, when: * `Foo` is a struct. * `T` implements `Unsize`. @@ -179,6 +219,7 @@ an implementation of `Unsize` for `T` will be provided: * If that field has type `Bar`, then `Bar` implements `Unsized>`. * T is not part of the type of any other fields. +r[coerce.unsized.pointer] Additionally, a type `Foo` can implement `CoerceUnsized>` when `T` implements `Unsize` or `CoerceUnsized>`. This allows it to provide an unsized coercion to `Foo`. @@ -189,6 +230,9 @@ unsized coercion to `Foo`. ## Least upper bound coercions +r[coerce.least-upper-bound] + +r[coerce.least-upper-bound] In some contexts, the compiler must coerce together multiple types to try and find the most general type. This is called a "Least Upper Bound" coercion. LUB coercion is used and only used in the following situations: @@ -199,15 +243,24 @@ LUB coercion is used and only used in the following situations: + To find the type for the return type of a closure with multiple return statements. + To check the type for the return type of a function with multiple return statements. +r[coerce.least-upper-bound.target] In each such case, there are a set of types `T0..Tn` to be mutually coerced -to some target type `T_t`, which is unknown to start. Computing the LUB +to some target type `T_t`, which is unknown to start. + +r[coerce.least-upper-bound.computation] +Computing the LUB coercion is done iteratively. The target type `T_t` begins as the type `T0`. For each new type `Ti`, we consider whether +r[coerce.least-upper-bound.computation-identity] + If `Ti` can be coerced to the current target type `T_t`, then no change is made. + +r[coerce.least-upper-bound.computation-replace] + Otherwise, check whether `T_t` can be coerced to `Ti`; if so, the `T_t` is changed to `Ti`. (This check is also conditioned on whether all of the source expressions considered thus far have implicit coercions.) + +r[coerce.least-upper-bound.computation-unify] + If not, try to compute a mutual supertype of `T_t` and `Ti`, which will become the new target type. ### Examples: From ce211839025a51aa275ae17984baa935da1ba88e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 09:47:19 -0400 Subject: [PATCH 098/189] Put `.intro` on identifier for intro paragraph of `coerce.least-upper-bound` --- src/type-coercions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type-coercions.md b/src/type-coercions.md index 5981170..a96e749 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -232,7 +232,7 @@ unsized coercion to `Foo`. r[coerce.least-upper-bound] -r[coerce.least-upper-bound] +r[coerce.least-upper-bound.intro] In some contexts, the compiler must coerce together multiple types to try and find the most general type. This is called a "Least Upper Bound" coercion. LUB coercion is used and only used in the following situations: From 98c1359f3f84c5d2e8cbdfa72f1a9a3c5b5d35a7 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 09:54:22 -0400 Subject: [PATCH 099/189] Add identifier syntax to linkage.md --- src/linkage.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/linkage.md b/src/linkage.md index 48a1c8e..894c5da 100644 --- a/src/linkage.md +++ b/src/linkage.md @@ -1,8 +1,11 @@ # Linkage +r[link] + > Note: This section is described more in terms of the compiler than of > the language. +r[link.intro] The compiler supports various methods to link crates together both statically and dynamically. This section will explore the various methods to link crates together, and more information about native libraries can be @@ -10,17 +13,20 @@ found in the [FFI section of the book][ffi]. [ffi]: ../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code +r[link.type] In one session of compilation, the compiler can generate multiple artifacts through the usage of either command line flags or the `crate_type` attribute. If one or more command line flags are specified, all `crate_type` attributes will be ignored in favor of only building the artifacts specified by command line. +r[link.bin] * `--crate-type=bin`, `#![crate_type = "bin"]` - A runnable executable will be produced. This requires that there is a `main` function in the crate which will be run when the program begins executing. This will link in all Rust and native dependencies, producing a single distributable binary. This is the default crate type. +r[link.lib] * `--crate-type=lib`, `#![crate_type = "lib"]` - A Rust library will be produced. This is an ambiguous concept as to what exactly is produced because a library can manifest itself in several forms. The purpose of this generic `lib` option @@ -30,6 +36,7 @@ be ignored in favor of only building the artifacts specified by command line. libraries, and the `lib` type can be seen as an alias for one of them (but the actual one is compiler-defined). +r[link.dylib] * `--crate-type=dylib`, `#![crate_type = "dylib"]` - A dynamic Rust library will be produced. This is different from the `lib` output type in that this forces dynamic library generation. The resulting dynamic library can be used as a @@ -37,6 +44,7 @@ be ignored in favor of only building the artifacts specified by command line. create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on Windows. +r[link.staticlib] * `--crate-type=staticlib`, `#![crate_type = "staticlib"]` - A static system library will be produced. This is different from other library outputs in that the compiler will never attempt to link to `staticlib` outputs. The @@ -62,12 +70,14 @@ be ignored in favor of only building the artifacts specified by command line. dependencies that is not actually used (e.g. `--gc-sections` or `-dead_strip` for macOS). +r[link.cdylib] * `--crate-type=cdylib`, `#![crate_type = "cdylib"]` - A dynamic system library will be produced. This is used when compiling a dynamic library to be loaded from another language. This output type will create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on Windows. +r[link.rlib] * `--crate-type=rlib`, `#![crate_type = "rlib"]` - A "Rust library" file will be produced. This is used as an intermediate artifact and can be thought of as a "static Rust library". These `rlib` files, unlike `staticlib` files, are @@ -76,6 +86,7 @@ be ignored in favor of only building the artifacts specified by command line. in dynamic libraries. This form of output is used to produce statically linked executables as well as `staticlib` outputs. +r[link.proc-macro] * `--crate-type=proc-macro`, `#![crate_type = "proc-macro"]` - The output produced is not specified, but if a `-L` path is provided to it then the compiler will recognize the output artifacts as a macro and it can be loaded @@ -87,6 +98,7 @@ be ignored in favor of only building the artifacts specified by command line. `x86_64-unknown-linux-gnu` even if the crate is a dependency of another crate being built for a different target. +r[link.repetition] Note that these outputs are stackable in the sense that if multiple are specified, then the compiler will produce each form of output without having to recompile. However, this only applies for outputs specified by the @@ -94,6 +106,7 @@ same method. If only `crate_type` attributes are specified, then they will all be built, but if one or more `--crate-type` command line flags are specified, then only those outputs will be built. +r[link.dependency] With all these different kinds of outputs, if crate A depends on crate B, then the compiler could find B in various different forms throughout the system. The only forms looked for by the compiler, however, are the `rlib` format and the @@ -102,6 +115,7 @@ compiler must at some point make a choice between these two formats. With this in mind, the compiler follows these rules when determining what format of dependencies will be used: +r[link.dependency-staticlib] 1. If a static library is being produced, all upstream dependencies are required to be available in `rlib` formats. This requirement stems from the reason that a dynamic library cannot be converted into a static format. @@ -110,6 +124,8 @@ dependencies will be used: library, and in this case warnings will be printed about all unlinked native dynamic dependencies. +r[link.dependency-rlib] + 2. If an `rlib` file is being produced, then there are no restrictions on what format the upstream dependencies are available in. It is simply required that all upstream dependencies be available for reading metadata from. @@ -118,11 +134,15 @@ dependencies will be used: dependencies. It wouldn't be very efficient for all `rlib` files to contain a copy of `libstd.rlib`! +r[link.dependency-prefer-dynamic] + 3. If an executable is being produced and the `-C prefer-dynamic` flag is not specified, then dependencies are first attempted to be found in the `rlib` format. If some dependencies are not available in an rlib format, then dynamic linking is attempted (see below). +r[link.dependency-dynamic] + 4. If a dynamic library or an executable that is being dynamically linked is being produced, then the compiler will attempt to reconcile the available dependencies in either the rlib or dylib format to create a final product. @@ -148,6 +168,9 @@ fine-grained control is desired over the output format of a crate. ## Static and dynamic C runtimes +r[link.crt] + +r[link.crt.intro] The standard library in general strives to support both statically linked and dynamically linked C runtimes for targets as appropriate. For example the `x86_64-pc-windows-msvc` and `x86_64-unknown-linux-musl` targets typically come @@ -162,6 +185,7 @@ default such as: * `i686-unknown-linux-musl` * `x86_64-unknown-linux-musl` +r[link.crt.crt-static] The linkage of the C runtime is configured to respect the `crt-static` target feature. These target features are typically configured from the command line via flags to the compiler itself. For example to enable a static runtime you @@ -177,10 +201,12 @@ whereas to link dynamically to the C runtime you would execute: rustc -C target-feature=-crt-static foo.rs ``` +r[link.crt.ineffective] Targets which do not support switching between linkage of the C runtime will ignore this flag. It's recommended to inspect the resulting binary to ensure that it's linked as you would expect after the compiler succeeds. +r[link.crt.target_feature] Crates may also learn about how the C runtime is being linked. Code on MSVC, for example, needs to be compiled differently (e.g. with `/MT` or `/MD`) depending on the runtime being linked. This is exported currently through the From 46774cd5dbcaf7a55820b7649d8d4a3b988ae206 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 10:31:34 -0400 Subject: [PATCH 100/189] Apply requested changes from T-lang/docs --- docs/authoring.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/authoring.md b/docs/authoring.md index 975ab78..b61be93 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -78,19 +78,16 @@ In the HTML, the rules are clickable just like headers. When assigning rules to new paragraphs, or when modifying rule names, use the following guidelines: 1. A rule applies to one core idea, which should be easily determined when reading the paragraph it is applied to, 2. Other than the "intro" paragraph, purely explanatory, expository, or exemplary content does not need a rule. If the expository paragraph isn't directly related to the previous, separate it with a hard (rendered) line break + * This content will be moved to `[!NOTE]` or more specific admonitions in the future. 3. Rust code examples and tests do not need their own rules 4. Notes do not need rules. For other admonition types, use the following guidelines: - * Warning: Omit the rule if and only if the warning follows from the previous paragraph. + * Warning: Omit the rule if the warning follows from the previous paragraph or if the warning is explanatory and doesn't introduce any new rules. * Target specific behaviour: Always include the rule * Edition differences: Always include the rule * Version history: Omit the rule if the present behaviour is explained in the immediately preceeding rule. 4. The following keywords should be used to identify paragraphs when unambiguous: * `intro`: The beginning paragraph of each section - should explain the construct being defined overall. * `syntax`: Syntax definitions or explanations when BNF syntax definitions are not used - * `safety` (instead of restriction): Stating that an operation is `unsafe` or the conditions under which it is `unsafe` - * `behavior`: Runtime effects of evaluating the construct in a well-defined manner - * `panics`: Conditions under which evaluating the construct causes a runtime panic - * `preconditions`: Conditions which must be satisfied for the evaluation of the construct to be well-defined * `namespace`: For items only, specifies the namespace(s) the item introduces a name in. May also be used elsewhere when defining a namespace (e.g. `r[attribute.diagnostic.namespace]`) 5. When a rule doesn't fall under the above keywords. or for section rule ids, name the subrule as follows: * If the rule is naming a specific Rust language construct (e.g. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s) @@ -99,9 +96,6 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo * Prefer using singular forms of words over plural unless the rule applies to a list or the construct is named as plural in the language (e.g. `r[attribute.diagnostic.lint.group]) * Whenever possible, don't use a name that conflicts with one of the above keywords, even if this violates the first bullet. * Use an appropriately discriptive, but short, name if the language does not provide one. -6. When a keyword applies, but multiple different rules in the same section would use the same keyword, prefix or suffix the rule with a descriptive id given above, separated with a `-` - * When the paragraph modifies a specific named construct or applies to a specific named construct only, prefix the rule with the name of the construct (e.g. `r[items.fn.params.self-constraint]`). - * When the paragraph refers to a specific named construct that applies the particular keyword behaviour, suffix the rule with the name of the construct ### Standard library links From 89f7e0593aa2132413fba6a7b3f7832744e0f27c Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 10:35:59 -0400 Subject: [PATCH 101/189] Document naming conventions for admonition identifiers --- docs/authoring.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/authoring.md b/docs/authoring.md index b61be93..3fe66ce 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -94,8 +94,10 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo * Other than rust language concepts with `_`s in the name, use `-` characters to separate words within a "subrule" * Whenever possible, do not repeat previous components of the rule * Prefer using singular forms of words over plural unless the rule applies to a list or the construct is named as plural in the language (e.g. `r[attribute.diagnostic.lint.group]) - * Whenever possible, don't use a name that conflicts with one of the above keywords, even if this violates the first bullet. + * Edition differences admonitions should typically be named by the edition referenced directly by the rule. If multiple editions are named, use the one for which the behaviour is defined by the admonition, and not by a previous paragraph + * Target Specific admonitions should typically be named by the least specific target property to which they apply (e.g. if a rule affects all x86 cpus, the rule name should include `x86` rather than separately listing `i586`, `i686` and `x86_64`, and if a rule applies to all ELF platforms, it should be named `elf` rather than listing every ELF os) * Use an appropriately discriptive, but short, name if the language does not provide one. + ### Standard library links From df666d9654ca5d36c4007e82902aed18b416327d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 28 Sep 2024 17:29:15 -0400 Subject: [PATCH 102/189] Mention `--print cfg` under set configuration options This often serves as the landing page for information about which `target_*` configuration options are available. Mention that `rustc` can print the exact options available for each target. --- src/conditional-compilation.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index f73f835..9775af5 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -58,6 +58,18 @@ configuration option from within the source code of the crate being compiled. > [!WARNING] > Arbitrarily-set configuration options can clash with compiler-set configuration options. For example, it is possible to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and have both `unix` and `windows` configuration options set at the same time. Doing this would be unwise. +Some default configuration values can be obtained from `rustc`: + +```text +rustc --print cfg # optionally, a --target can be specified +target_abi="" +target_arch="aarch64" +target_endian="little" +target_env="" +target_family="unix" +... +``` + ### `target_arch` Key-value option set once with the target's CPU architecture. The value is From fce7b3539aeb796efe67544ec511d2b11155bba9 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 29 Sep 2024 22:34:46 +0200 Subject: [PATCH 103/189] Clarify definition of "immutable bytes" --- src/behavior-considered-undefined.md | 4 +++- src/destructors.md | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 63fa28f..2d252ed 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -40,7 +40,8 @@ undefined behavior, it is *unsound*. All this also applies when values of these types are passed in a (nested) field of a compound type, but not behind pointer indirections. -* Mutating immutable bytes. All bytes inside a [`const`] item or within an implicitly [const-promoted] expression are immutable. +* Mutating immutable bytes. + All bytes reachable through a [const-promoted] expression are immutable, as well as bytes reachable through borrows in `static` and `const` initializers that have been [lifetime-extended] to `'static`. The bytes owned by an immutable binding or immutable `static` are immutable, unless those bytes are part of an [`UnsafeCell`]. Moreover, the bytes [pointed to] by a shared reference, including transitively through other references (both shared and mutable) and `Box`es, are immutable; transitivity includes those references stored in fields of compound types. @@ -179,3 +180,4 @@ reading uninitialized memory is permitted are inside `union`s and in "padding" [project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions [project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions [const-promoted]: destructors.md#constant-promotion +[lifetime-extended]: destructors.md#temporary-lifetime-extension diff --git a/src/destructors.md b/src/destructors.md index a536221..7cdfaee 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -325,6 +325,18 @@ let x = &mut 0; println!("{}", x); ``` +r[destructors.scope.lifetime-extension.static] +Lifetime extension also applies to `static` and `const` items, where it +makes temporaries live until the end of the program. For example: + +```rust +const C: &Vec = &Vec::new(); +// Usually this would be a dangling reference as the `Vec` would only +// exist inside the initializer expression of `C`, but instead the +// borrow gets lifetime-extended so it effectively has `'static` lifetime. +println!("{:?}", C); +``` + r[destructors.scope.lifetime-extension.sub-expressions] If a [borrow][borrow expression], [dereference][dereference expression], [field][field expression], or [tuple indexing expression] has an extended From fd37367dc4b7f2b19b89e89bb25fe054aafa93f6 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 1 Oct 2024 09:40:35 -0700 Subject: [PATCH 104/189] Add two more WebAssembly features to the list of accepted ones This is intended to be a sibling PR to rust-lang/rust#131080 to update the reference documentation for wasm supporting two more features. --- src/attributes/codegen.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index f30c296..9309e25 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -282,6 +282,8 @@ Feature | Implicitly Enables | Description `relaxed-simd` | `simd128` | [WebAssembly relaxed simd proposal][relaxed-simd] `sign-ext` | | [WebAssembly sign extension operators Proposal][sign-ext] `simd128` | | [WebAssembly simd proposal][simd128] +`multivalue` | | [WebAssembly multivalue proposal][multivalue] +`reference-types` | | [WebAssembly reference-types proposal][reference-types] [bulk-memory]: https://github.com/WebAssembly/bulk-memory-operations [extended-const]: https://github.com/WebAssembly/extended-const @@ -290,6 +292,8 @@ Feature | Implicitly Enables | Description [relaxed-simd]: https://github.com/WebAssembly/relaxed-simd [sign-ext]: https://github.com/WebAssembly/sign-extension-ops [simd128]: https://github.com/webassembly/simd +[reference-types]: https://github.com/webassembly/reference-types +[multivalue]: https://github.com/webassembly/multi-value ### Additional information From 1313d2d2934f9f60dc7902a1266e0f8ae7853327 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 1 Oct 2024 15:58:06 -0700 Subject: [PATCH 105/189] Also add info on the tail-call proposal --- src/attributes/codegen.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 9309e25..c8174a4 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -284,6 +284,7 @@ Feature | Implicitly Enables | Description `simd128` | | [WebAssembly simd proposal][simd128] `multivalue` | | [WebAssembly multivalue proposal][multivalue] `reference-types` | | [WebAssembly reference-types proposal][reference-types] +`tail-call` | | [WebAssembly tail-call proposal][tail-call] [bulk-memory]: https://github.com/WebAssembly/bulk-memory-operations [extended-const]: https://github.com/WebAssembly/extended-const @@ -293,6 +294,7 @@ Feature | Implicitly Enables | Description [sign-ext]: https://github.com/WebAssembly/sign-extension-ops [simd128]: https://github.com/webassembly/simd [reference-types]: https://github.com/webassembly/reference-types +[tail-call]: https://github.com/webassembly/tail-call [multivalue]: https://github.com/webassembly/multi-value ### Additional information From 58508232f1b781bbc6d54fe510ec9f14ce4f4c92 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 2 Oct 2024 10:57:20 -0700 Subject: [PATCH 106/189] Fix misspellings --- src/macros-by-example.md | 4 ++-- src/procedural-macros.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 6009eed..17e7388 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -412,7 +412,7 @@ by other crates, either by path or by `#[macro_use]` as described above. r[macro.decl.hygiene] -r[macreo.decl.hygiene.intro] +r[macro.decl.hygiene.intro] By default, all identifiers referred to in a macro are expanded as-is, and are looked up at the macro's invocation site. This can lead to issues if a macro refers to an item or macro which isn't in scope at the invocation site. To @@ -480,7 +480,7 @@ fn foo() {} > modified to use `$crate` or `local_inner_macros` to work well with path-based > imports. -r[macro.decl.hygeine.local_inner_macros] +r[macro.decl.hygiene.local_inner_macros] When a macro is exported, the `#[macro_export]` attribute can have the `local_inner_macros` keyword added to automatically prefix all contained macro invocations with `$crate::`. This is intended primarily as a tool to migrate diff --git a/src/procedural-macros.md b/src/procedural-macros.md index 0421fc7..a9b24e1 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -348,7 +348,7 @@ Token trees in procedural macros are defined as and floating point literals. - Identifiers, including keywords (`ident`, `r#ident`, `fn`) -r[macro.proc.token.converstion-intro] +r[macro.proc.token.conversion-intro] Mismatches between these two definitions are accounted for when token streams are passed to and from procedural macros. \ Note that the conversions below may happen lazily, so they might not happen if From 1aad33f1cc9916497993d9c4109ce371c69d9beb Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 2 Oct 2024 11:12:35 -0700 Subject: [PATCH 107/189] Some minor rule identifier tweaks Shooting for some consistency with these. --- src/procedural-macros.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/procedural-macros.md b/src/procedural-macros.md index a9b24e1..0ae6e26 100644 --- a/src/procedural-macros.md +++ b/src/procedural-macros.md @@ -348,13 +348,13 @@ Token trees in procedural macros are defined as and floating point literals. - Identifiers, including keywords (`ident`, `r#ident`, `fn`) -r[macro.proc.token.conversion-intro] +r[macro.proc.token.conversion.intro] Mismatches between these two definitions are accounted for when token streams are passed to and from procedural macros. \ Note that the conversions below may happen lazily, so they might not happen if the tokens are not actually inspected. -r[macro.proc.token.conversion] +r[macro.proc.token.conversion.to-proc_macro] When passed to a proc-macro - All multi-character operators are broken into single characters. - Lifetimes are broken into a `'` character and an identifier. @@ -366,7 +366,7 @@ When passed to a proc-macro - `tt` and `ident` substitutions are never wrapped into such groups and always represented as their underlying token trees. -r[macro.proc.token.emission] +r[macro.proc.token.conversion.from-proc_macro] When emitted from a proc macro - Punctuation characters are glued into multi-character operators when applicable. From 8f13367e123cff0555bafd0585b1e35e02bc5773 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 2 Oct 2024 13:37:46 -0700 Subject: [PATCH 108/189] Add `expr_2021` macro fragment specifier --- src/macros-by-example.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 17e7388..dad88a5 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -30,7 +30,7 @@ r[macro.decl.syntax] >    | `$` `(` _MacroMatch_+ `)` _MacroRepSep_? _MacroRepOp_ > > _MacroFragSpec_ :\ ->       `block` | `expr` | `ident` | `item` | `lifetime` | `literal`\ +>       `block` | `expr` | `expr_2021` | `ident` | `item` | `lifetime` | `literal`\ >    | `meta` | `pat` | `pat_param` | `path` | `stmt` | `tt` | `ty` | `vis` > > _MacroRepSep_ :\ @@ -143,7 +143,8 @@ Valid fragment specifiers are: statements that require semicolons) * `pat_param`: a [_PatternNoTopAlt_] * `pat`: at least any [_PatternNoTopAlt_], and possibly more depending on edition - * `expr`: an [_Expression_] + * `expr`: an [_Expression_] except [_UnderscoreExpression_] and [_ConstBlockExpression_] (see [macro.decl.meta.expr-underscore]) + * `expr_2021`: same as `expr` (see [macro.decl.meta.edition2021]) * `ty`: a [_Type_] * `ident`: an [IDENTIFIER_OR_KEYWORD] or [RAW_IDENTIFIER] * `path`: a [_TypePath_] style path @@ -175,6 +176,8 @@ r[macro.decl.meta.edition2021] > Before the 2021 edition, they match exactly the same fragments as `pat_param` (that is, they accept [_PatternNoTopAlt_]). > > The relevant edition is the one in effect for the `macro_rules!` definition. +> +> The `expr_2021` fragment specifier exists to maintain backwards compatibility with editions before 2024. ## Repetitions @@ -572,6 +575,7 @@ For more detail, see the [formal specification]. [Repetitions]: #repetitions [_Attr_]: attributes.md [_BlockExpression_]: expressions/block-expr.md +[_ConstBlockExpression_]: expressions/block-expr.md#const-blocks [_DelimTokenTree_]: macros.md [_Expression_]: expressions.md [_Item_]: items.md From 176acfa228a8284e01bb214ae8b5d55cb7a46c9f Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 20 Aug 2024 11:59:03 -0700 Subject: [PATCH 109/189] Add expr_2021 to FOLLOW set rules --- src/macro-ambiguity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macro-ambiguity.md b/src/macro-ambiguity.md index 01ae288..d8ca480 100644 --- a/src/macro-ambiguity.md +++ b/src/macro-ambiguity.md @@ -325,7 +325,7 @@ represent simple nonterminals with the given fragment specifier. * FOLLOW(pat) = {`=>`, `,`, `=`, `|`, `if`, `in`}`. - * FOLLOW(expr) = FOLLOW(stmt) = {`=>`, `,`, `;`}`. + * FOLLOW(expr) = FOLLOW(expr_2021) = FOLLOW(stmt) = {`=>`, `,`, `;`}`. * FOLLOW(ty) = FOLLOW(path) = {`{`, `[`, `,`, `=>`, `:`, `=`, `>`, `>>`, `;`, `|`, `as`, `where`, block nonterminals}. From 97ad750e5aa82541beb203e537abaf711bb8a9f7 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 2 Oct 2024 14:02:12 -0700 Subject: [PATCH 110/189] Sort macro fragment specifiers --- src/macros-by-example.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index dad88a5..2f6a9fc 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -137,22 +137,21 @@ fragment of the kind specified and binds it to the metavariable `$`_name_. r[macro.decl.meta.specifier] Valid fragment specifiers are: - * `item`: an [_Item_] * `block`: a [_BlockExpression_] - * `stmt`: a [_Statement_] without the trailing semicolon (except for item - statements that require semicolons) - * `pat_param`: a [_PatternNoTopAlt_] - * `pat`: at least any [_PatternNoTopAlt_], and possibly more depending on edition * `expr`: an [_Expression_] except [_UnderscoreExpression_] and [_ConstBlockExpression_] (see [macro.decl.meta.expr-underscore]) * `expr_2021`: same as `expr` (see [macro.decl.meta.edition2021]) - * `ty`: a [_Type_] * `ident`: an [IDENTIFIER_OR_KEYWORD] or [RAW_IDENTIFIER] + * `item`: an [_Item_] + * `lifetime`: a [LIFETIME_TOKEN] + * `literal`: matches `-`?[_LiteralExpression_] + * `meta`: an [_Attr_], the contents of an attribute + * `pat`: at least any [_PatternNoTopAlt_], and possibly more depending on edition + * `pat_param`: a [_PatternNoTopAlt_] * `path`: a [_TypePath_] style path + * `stmt`: a [_Statement_] without the trailing semicolon (except for item statements that require semicolons) * `tt`: a [_TokenTree_] (a single [token] or tokens in matching delimiters `()`, `[]`, or `{}`) - * `meta`: an [_Attr_], the contents of an attribute - * `lifetime`: a [LIFETIME_TOKEN] + * `ty`: a [_Type_] * `vis`: a possibly empty [_Visibility_] qualifier - * `literal`: matches `-`?[_LiteralExpression_] r[macro.decl.meta.transcription] In the transcriber, metavariables are referred to simply by `$`_name_, since From 0c83a247e2609cafa7335fcd519d734eb920efbd Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 3 Oct 2024 08:58:58 -0700 Subject: [PATCH 111/189] Fix typos and formatting. --- docs/authoring.md | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/authoring.md b/docs/authoring.md index 3fe66ce..9806894 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -76,28 +76,29 @@ Rules can be linked to by their ID using markdown such as `[foo.bar]`. There are In the HTML, the rules are clickable just like headers. When assigning rules to new paragraphs, or when modifying rule names, use the following guidelines: -1. A rule applies to one core idea, which should be easily determined when reading the paragraph it is applied to, -2. Other than the "intro" paragraph, purely explanatory, expository, or exemplary content does not need a rule. If the expository paragraph isn't directly related to the previous, separate it with a hard (rendered) line break + +1. A rule applies to one core idea, which should be easily determined when reading the paragraph it is applied to. +2. Other than the "intro" paragraph, purely explanatory, expository, or exemplary content does not need a rule. If the expository paragraph isn't directly related to the previous, separate it with a hard (rendered) line break. * This content will be moved to `[!NOTE]` or more specific admonitions in the future. -3. Rust code examples and tests do not need their own rules -4. Notes do not need rules. For other admonition types, use the following guidelines: +3. Rust code examples and tests do not need their own rules. +4. Use the following guidelines for admonitions: + * Notes: Do not include a rule. * Warning: Omit the rule if the warning follows from the previous paragraph or if the warning is explanatory and doesn't introduce any new rules. - * Target specific behaviour: Always include the rule - * Edition differences: Always include the rule - * Version history: Omit the rule if the present behaviour is explained in the immediately preceeding rule. -4. The following keywords should be used to identify paragraphs when unambiguous: + * Target specific behavior: Always include the rule. + * Edition differences: Always include the rule. + * Version history: Omit the rule if the present behavior is explained in the immediately preceding rule. +5. The following keywords should be used to identify paragraphs when unambiguous: * `intro`: The beginning paragraph of each section - should explain the construct being defined overall. - * `syntax`: Syntax definitions or explanations when BNF syntax definitions are not used - * `namespace`: For items only, specifies the namespace(s) the item introduces a name in. May also be used elsewhere when defining a namespace (e.g. `r[attribute.diagnostic.namespace]`) -5. When a rule doesn't fall under the above keywords. or for section rule ids, name the subrule as follows: - * If the rule is naming a specific Rust language construct (e.g. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s) - * Other than rust language concepts with `_`s in the name, use `-` characters to separate words within a "subrule" - * Whenever possible, do not repeat previous components of the rule - * Prefer using singular forms of words over plural unless the rule applies to a list or the construct is named as plural in the language (e.g. `r[attribute.diagnostic.lint.group]) - * Edition differences admonitions should typically be named by the edition referenced directly by the rule. If multiple editions are named, use the one for which the behaviour is defined by the admonition, and not by a previous paragraph - * Target Specific admonitions should typically be named by the least specific target property to which they apply (e.g. if a rule affects all x86 cpus, the rule name should include `x86` rather than separately listing `i586`, `i686` and `x86_64`, and if a rule applies to all ELF platforms, it should be named `elf` rather than listing every ELF os) - * Use an appropriately discriptive, but short, name if the language does not provide one. - + * `syntax`: Syntax definitions or explanations when BNF syntax definitions are not used. + * `namespace`: For items only, specifies the namespace(s) the item introduces a name in. May also be used elsewhere when defining a namespace (e.g. `r[attribute.diagnostic.namespace]`). +6. When a rule doesn't fall under the above keywords, or for section rule ids, name the subrule as follows: + * If the rule is naming a specific Rust language construct (e.g. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s). + * Other than Rust language concepts with `_`s in the name, use `-` characters to separate words within a "subrule". + * Whenever possible, do not repeat previous components of the rule. + * Prefer using singular forms of words over plural unless the rule applies to a list or the construct is named as plural in the language (e.g. `r[attribute.diagnostic.lint.group]). + * Edition differences admonitions should typically be named by the edition referenced directly by the rule. If multiple editions are named, use the one for which the behavior is defined by the admonition, and not by a previous paragraph. + * Target specific admonitions should typically be named by the least specific target property to which they apply (e.g. if a rule affects all x86 CPUs, the rule name should include `x86` rather than separately listing `i586`, `i686` and `x86_64`, and if a rule applies to all ELF platforms, it should be named `elf` rather than listing every ELF OS). + * Use an appropriately descriptive, but short, name if the language does not provide one. ### Standard library links From ddca6090d9855fa8e9fa4e85283201c59b22a45b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 3 Oct 2024 08:59:47 -0700 Subject: [PATCH 112/189] Remove "version history" We have not specifically decided on including version information, or how it will be done. --- docs/authoring.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/authoring.md b/docs/authoring.md index 9806894..158ae82 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -86,7 +86,6 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo * Warning: Omit the rule if the warning follows from the previous paragraph or if the warning is explanatory and doesn't introduce any new rules. * Target specific behavior: Always include the rule. * Edition differences: Always include the rule. - * Version history: Omit the rule if the present behavior is explained in the immediately preceding rule. 5. The following keywords should be used to identify paragraphs when unambiguous: * `intro`: The beginning paragraph of each section - should explain the construct being defined overall. * `syntax`: Syntax definitions or explanations when BNF syntax definitions are not used. From d8db08a4b864860de362330779a77c481c228214 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 3 Oct 2024 09:03:34 -0700 Subject: [PATCH 113/189] Remove "singular forms" We don't agree on this particular point, as we have been using plurals almost everywhere. There are also some subtle complexities with what the specific guidelines might be. --- docs/authoring.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/authoring.md b/docs/authoring.md index 158ae82..1495bc2 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -94,7 +94,6 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo * If the rule is naming a specific Rust language construct (e.g. an attribute, standard library type/function, or keyword-introduced concept), use the construct as named in the language, appropriately case-adjusted (but do not replace `_`s with `-`s). * Other than Rust language concepts with `_`s in the name, use `-` characters to separate words within a "subrule". * Whenever possible, do not repeat previous components of the rule. - * Prefer using singular forms of words over plural unless the rule applies to a list or the construct is named as plural in the language (e.g. `r[attribute.diagnostic.lint.group]). * Edition differences admonitions should typically be named by the edition referenced directly by the rule. If multiple editions are named, use the one for which the behavior is defined by the admonition, and not by a previous paragraph. * Target specific admonitions should typically be named by the least specific target property to which they apply (e.g. if a rule affects all x86 CPUs, the rule name should include `x86` rather than separately listing `i586`, `i686` and `x86_64`, and if a rule applies to all ELF platforms, it should be named `elf` rather than listing every ELF OS). * Use an appropriately descriptive, but short, name if the language does not provide one. From 8f5902042d085d12305b115c87495b0bacb6816d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 5 Oct 2024 01:53:00 +0900 Subject: [PATCH 114/189] Fix inline-assembly documentation for LoongArch --- 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 3ad16a6..7822394 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -484,7 +484,7 @@ The following ABIs can be used with `clobber_abi`: | AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x18`\*, `x30`, `v[0-31]`, `p[0-15]`, `ffr` | | ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` | | RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` | -| LoongArch | `"C"`, `"system"`, `"efiapi"` | `$r1`, `$r[4-20]`, `$f[0-23]` | +| LoongArch | `"C"`, `"system"` | `$r1`, `$r[4-20]`, `$f[0-23]` | > Notes: > - On AArch64 `x18` only included in the clobber list if it is not considered as a reserved register on the target. From fe8c290a4a6fff5e6c2b57f7981e6c29e391d3c2 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 8 Oct 2024 09:17:20 -0700 Subject: [PATCH 115/189] Add preview artifacts in CI --- .github/workflows/main.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0dfd2da..ccb3d0c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -98,6 +98,34 @@ jobs: working-directory: ./mdbook-spec run: cargo fmt --check + preview: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Update rustup + run: rustup self update + - name: Install Rust + run: | + rustup set profile minimal + rustup toolchain install nightly + rustup default nightly + - name: Install mdbook + run: | + mkdir bin + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v${MDBOOK_VERSION}/mdbook-v${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin + echo "$(pwd)/bin" >> $GITHUB_PATH + - name: Build the book + env: + SPEC_RELATIVE: 0 + run: mdbook build --dest-dir dist/preview-${{ github.event.pull_request.number }} + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: preview-${{ github.event.pull_request.number }} + overwrite: true + path: dist + # The success job is here to consolidate the total success/failure state of # all other jobs. This job is then included in the GitHub branch protection # rule which prevents merges unless all other jobs are passing. This makes @@ -110,6 +138,7 @@ jobs: - code-tests - style-tests - mdbook-spec + # preview is explicitly excluded here since it doesn't run on merge runs-on: ubuntu-latest steps: - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' From f6d15b191119b0dc9e037260a08bcb7f3133f7bb Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 8 Oct 2024 13:38:49 -0700 Subject: [PATCH 116/189] Add restriction for cfg_attr with crate_type and crate_name --- src/conditional-compilation.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index f73f835..97f018b 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -339,6 +339,8 @@ fn bewitched() {} The `cfg_attr` attribute is allowed anywhere attributes are allowed. +The [`crate_type`] and [`crate_name`] attributes cannot be used with `cfg_attr`. + ### The `cfg` macro The built-in `cfg` macro takes in a single configuration predicate and evaluates @@ -369,6 +371,8 @@ println!("I'm running on a {} machine!", machine_kind); [`cfg`]: #the-cfg-attribute [`cfg` macro]: #the-cfg-macro [`cfg_attr`]: #the-cfg_attr-attribute +[`crate_name`]: crates-and-source-files.md#the-crate_name-attribute +[`crate_type`]: linkage.md [`target_feature` attribute]: attributes/codegen.md#the-target_feature-attribute [attribute]: attributes.md [attributes]: attributes.md From 9bbd3dde23e4da52bd3494313c2ee686605c6d6e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 9 Oct 2024 23:42:26 -0400 Subject: [PATCH 117/189] Apply suggestions from code review Co-authored-by: Eric Huss --- src/type-layout.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 1b05342..6e91537 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -136,7 +136,7 @@ Trait objects have the same layout as the value the trait object is of. ## Closure Layout -r[kayout.closure] +r[layout.closure] Closures have no layout guarantees. @@ -260,7 +260,7 @@ is [zero-variant enums] for which the `C` representation is an error. r[layout.repr.c.struct] -r[layour.repr.c.struct.align] +r[layout.repr.c.struct.align] The alignment of the struct is the alignment of the most-aligned field in it. r[layout.repr.c.struct.size-field-offset] From f016dd2e69e53e4153394c19125d6c4bc47931ca Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 11 Oct 2024 23:13:50 +0200 Subject: [PATCH 118/189] trait bounds grammar: make `?` and `for<>` mutually exclusive --- src/trait-bounds.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 019a2f7..b0d667d 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -8,10 +8,10 @@ >       _Lifetime_ | _TraitBound_ | _UseBound_ > > _TraitBound_ :\ ->       `?`? -> [_ForLifetimes_](#higher-ranked-trait-bounds)? [_TypePath_]\ ->    | `(` `?`? -> [_ForLifetimes_](#higher-ranked-trait-bounds)? [_TypePath_] `)` +>       ( `?` | +> [_ForLifetimes_](#higher-ranked-trait-bounds) )? [_TypePath_]\ +>    | `(` ( `?` | +> [_ForLifetimes_](#higher-ranked-trait-bounds) )? [_TypePath_] `)` > > _LifetimeBounds_ :\ >    ( _Lifetime_ `+` )\* _Lifetime_? From 0eaa42edd0fadc3ceb01fd2a0955786ff1ed52d9 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 7 Oct 2024 15:57:10 -0700 Subject: [PATCH 119/189] Move rules handling to its own module There should otherwise be no code changes here. --- mdbook-spec/src/lib.rs | 39 +------------------------------- mdbook-spec/src/rules.rs | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 38 deletions(-) create mode 100644 mdbook-spec/src/rules.rs diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 5234531..03b9234 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -11,11 +11,9 @@ use std::collections::BTreeMap; use std::io; use std::path::PathBuf; +mod rules; mod std_links; -/// The Regex for rules like `r[foo]`. -static RULE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)^r\[([^]]+)]$").unwrap()); - /// The Regex for the syntax for blockquotes that have a specific CSS class, /// like `> [!WARNING]`. static ADMONITION_RE: Lazy = Lazy::new(|| { @@ -57,41 +55,6 @@ impl Spec { } } - /// Converts lines that start with `r[…]` into a "rule" which has special - /// styling and can be linked to. - fn rule_definitions( - &self, - chapter: &Chapter, - found_rules: &mut BTreeMap, - ) -> String { - let source_path = chapter.source_path.clone().unwrap_or_default(); - let path = chapter.path.clone().unwrap_or_default(); - RULE_RE - .replace_all(&chapter.content, |caps: &Captures<'_>| { - let rule_id = &caps[1]; - if let Some((old, _)) = - found_rules.insert(rule_id.to_string(), (source_path.clone(), path.clone())) - { - let message = format!( - "rule `{rule_id}` defined multiple times\n\ - First location: {old:?}\n\ - Second location: {source_path:?}" - ); - if self.deny_warnings { - panic!("error: {message}"); - } else { - eprintln!("warning: {message}"); - } - } - format!( - "

    \ - [{rule_id}]\ -
    \n" - ) - }) - .to_string() - } - /// Generates link references to all rules on all pages, so you can easily /// refer to rules anywhere in the book. fn auto_link_references( diff --git a/mdbook-spec/src/rules.rs b/mdbook-spec/src/rules.rs new file mode 100644 index 0000000..65c53c7 --- /dev/null +++ b/mdbook-spec/src/rules.rs @@ -0,0 +1,48 @@ +//! Handling for rule identifiers. + +use crate::Spec; +use mdbook::book::Chapter; +use once_cell::sync::Lazy; +use regex::{Captures, Regex}; +use std::collections::BTreeMap; +use std::path::PathBuf; + +/// The Regex for rules like `r[foo]`. +static RULE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)^r\[([^]]+)]$").unwrap()); + +impl Spec { + /// Converts lines that start with `r[…]` into a "rule" which has special + /// styling and can be linked to. + pub fn rule_definitions( + &self, + chapter: &Chapter, + found_rules: &mut BTreeMap, + ) -> String { + let source_path = chapter.source_path.clone().unwrap_or_default(); + let path = chapter.path.clone().unwrap_or_default(); + RULE_RE + .replace_all(&chapter.content, |caps: &Captures<'_>| { + let rule_id = &caps[1]; + if let Some((old, _)) = + found_rules.insert(rule_id.to_string(), (source_path.clone(), path.clone())) + { + let message = format!( + "rule `{rule_id}` defined multiple times\n\ + First location: {old:?}\n\ + Second location: {source_path:?}" + ); + if self.deny_warnings { + panic!("error: {message}"); + } else { + eprintln!("warning: {message}"); + } + } + format!( + "
    \ + [{rule_id}]\ +
    \n" + ) + }) + .to_string() + } +} From 9373134beb3f2c2f2a52f6f6ee5b3d98c81fdfd1 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 7 Oct 2024 16:00:44 -0700 Subject: [PATCH 120/189] Move Spec creation out of main This is in preparation for error handling in future commits. --- mdbook-spec/src/lib.rs | 11 ++++++----- mdbook-spec/src/main.rs | 4 +--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 03b9234..e569431 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -1,5 +1,6 @@ #![deny(rust_2018_idioms, unused_lifetimes)] +use anyhow::Result; use mdbook::book::{Book, Chapter}; use mdbook::errors::Error; use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext}; @@ -20,7 +21,8 @@ static ADMONITION_RE: Lazy = Lazy::new(|| { Regex::new(r"(?m)^ *> \[!(?[^]]+)\]\n(?
    (?: *>.*\n)+)").unwrap() }); -pub fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> { +pub fn handle_preprocessing() -> Result<(), Error> { + let pre = Spec::new()?; let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?; let book_version = Version::parse(&ctx.mdbook_version)?; @@ -49,10 +51,9 @@ pub struct Spec { } impl Spec { - pub fn new() -> Spec { - Spec { - deny_warnings: std::env::var("SPEC_DENY_WARNINGS").as_deref() == Ok("1"), - } + fn new() -> Result { + let deny_warnings = std::env::var("SPEC_DENY_WARNINGS").as_deref() == Ok("1"); + Ok(Spec { deny_warnings }) } /// Generates link references to all rules on all pages, so you can easily diff --git a/mdbook-spec/src/main.rs b/mdbook-spec/src/main.rs index 56e11d7..83ac830 100644 --- a/mdbook-spec/src/main.rs +++ b/mdbook-spec/src/main.rs @@ -12,9 +12,7 @@ fn main() { None => {} } - let preprocessor = mdbook_spec::Spec::new(); - - if let Err(e) = mdbook_spec::handle_preprocessing(&preprocessor) { + if let Err(e) = mdbook_spec::handle_preprocessing() { eprintln!("{}", e); std::process::exit(1); } From 5dc3dd9397b8d9677396f4055d55dbea3a85c85b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 7 Oct 2024 16:09:21 -0700 Subject: [PATCH 121/189] Move rule collection into a separate pass with a new structure This adds a "Rules" struct which encapsulates the rules in the document. This also removes some of the mutable variables. This is paving the way for future updates which extends information and processing about rules. --- mdbook-spec/src/lib.rs | 30 +++++---------- mdbook-spec/src/rules.rs | 79 ++++++++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index e569431..add3b25 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -1,5 +1,6 @@ #![deny(rust_2018_idioms, unused_lifetimes)] +use crate::rules::Rules; use anyhow::Result; use mdbook::book::{Book, Chapter}; use mdbook::errors::Error; @@ -8,9 +9,7 @@ use mdbook::BookItem; use once_cell::sync::Lazy; use regex::{Captures, Regex}; use semver::{Version, VersionReq}; -use std::collections::BTreeMap; use std::io; -use std::path::PathBuf; mod rules; mod std_links; @@ -58,13 +57,10 @@ impl Spec { /// Generates link references to all rules on all pages, so you can easily /// refer to rules anywhere in the book. - fn auto_link_references( - &self, - chapter: &Chapter, - found_rules: &BTreeMap, - ) -> String { + fn auto_link_references(&self, chapter: &Chapter, rules: &Rules) -> String { let current_path = chapter.path.as_ref().unwrap().parent().unwrap(); - let definitions: String = found_rules + let definitions: String = rules + .def_paths .iter() .map(|(rule_id, (_, path))| { let relative = pathdiff::diff_paths(path, current_path).unwrap(); @@ -125,7 +121,8 @@ impl Preprocessor for Spec { } fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result { - let mut found_rules = BTreeMap::new(); + let rules = self.collect_rules(&book); + book.for_each_mut(|item| { let BookItem::Chapter(ch) = item else { return; @@ -133,20 +130,11 @@ impl Preprocessor for Spec { if ch.is_draft_chapter() { return; } - ch.content = self.rule_definitions(&ch, &mut found_rules); ch.content = self.admonitions(&ch); + ch.content = self.auto_link_references(&ch, &rules); + ch.content = self.render_rule_definitions(&ch.content); }); - // This is a separate pass because it relies on the modifications of - // the previous passes. - book.for_each_mut(|item| { - let BookItem::Chapter(ch) = item else { - return; - }; - if ch.is_draft_chapter() { - return; - } - ch.content = self.auto_link_references(&ch, &found_rules); - }); + // Final pass will resolve everything as a std link (or error if the // link is unknown). std_links::std_links(&mut book); diff --git a/mdbook-spec/src/rules.rs b/mdbook-spec/src/rules.rs index 65c53c7..fdbd2f7 100644 --- a/mdbook-spec/src/rules.rs +++ b/mdbook-spec/src/rules.rs @@ -1,7 +1,8 @@ //! Handling for rule identifiers. use crate::Spec; -use mdbook::book::Chapter; +use mdbook::book::Book; +use mdbook::BookItem; use once_cell::sync::Lazy; use regex::{Captures, Regex}; use std::collections::BTreeMap; @@ -10,33 +11,65 @@ use std::path::PathBuf; /// The Regex for rules like `r[foo]`. static RULE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)^r\[([^]]+)]$").unwrap()); +/// The set of rules defined in the reference. +#[derive(Default)] +pub struct Rules { + /// A mapping from a rule identifier to a tuple of `(source_path, path)`. + /// + /// `source_path` is the path to the markdown source file relative to the + /// `SUMMARY.md`. + /// + /// `path` is the same as `source_path`, except filenames like `README.md` + /// are translated to `index.md`. Which to use depends on if you are + /// trying to access the source files (`source_path`), or creating links + /// in the output (`path`). + pub def_paths: BTreeMap, +} + impl Spec { + /// Collects all rule definitions in the book. + pub fn collect_rules(&self, book: &Book) -> Rules { + let mut rules = Rules::default(); + for item in book.iter() { + let BookItem::Chapter(ch) = item else { + continue; + }; + if ch.is_draft_chapter() { + continue; + } + RULE_RE + .captures_iter(&ch.content) + .for_each(|caps: Captures<'_>| { + let rule_id = &caps[1]; + let source_path = ch.source_path.clone().unwrap_or_default(); + let path = ch.path.clone().unwrap_or_default(); + if let Some((old, _)) = rules + .def_paths + .insert(rule_id.to_string(), (source_path.clone(), path.clone())) + { + let message = format!( + "rule `{rule_id}` defined multiple times\n\ + First location: {old:?}\n\ + Second location: {source_path:?}" + ); + if self.deny_warnings { + panic!("error: {message}"); + } else { + eprintln!("warning: {message}"); + } + } + }); + } + + rules + } + /// Converts lines that start with `r[…]` into a "rule" which has special /// styling and can be linked to. - pub fn rule_definitions( - &self, - chapter: &Chapter, - found_rules: &mut BTreeMap, - ) -> String { - let source_path = chapter.source_path.clone().unwrap_or_default(); - let path = chapter.path.clone().unwrap_or_default(); + pub fn render_rule_definitions(&self, content: &str) -> String { RULE_RE - .replace_all(&chapter.content, |caps: &Captures<'_>| { + .replace_all(content, |caps: &Captures<'_>| { let rule_id = &caps[1]; - if let Some((old, _)) = - found_rules.insert(rule_id.to_string(), (source_path.clone(), path.clone())) - { - let message = format!( - "rule `{rule_id}` defined multiple times\n\ - First location: {old:?}\n\ - Second location: {source_path:?}" - ); - if self.deny_warnings { - panic!("error: {message}"); - } else { - eprintln!("warning: {message}"); - } - } format!( "
    \ [{rule_id}]\ From 6fd3f1266f5a48ec1ba0d2754a9d7cab796be6dc Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 7 Oct 2024 16:15:19 -0700 Subject: [PATCH 122/189] Add tracking of rule prefixes This adds tracking of rule prefixes (like `asm.ts-args` is an interior prefix of `asm.ts-args.syntax`). This will be used for test linking, to check for tests that link to these. I'm not sure what we'll want to do with these long-term, whether we want to allow linking these "uber" rules, or remove them, or just warn about them. --- mdbook-spec/src/rules.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mdbook-spec/src/rules.rs b/mdbook-spec/src/rules.rs index fdbd2f7..ac402b8 100644 --- a/mdbook-spec/src/rules.rs +++ b/mdbook-spec/src/rules.rs @@ -5,7 +5,7 @@ use mdbook::book::Book; use mdbook::BookItem; use once_cell::sync::Lazy; use regex::{Captures, Regex}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; use std::path::PathBuf; /// The Regex for rules like `r[foo]`. @@ -24,6 +24,10 @@ pub struct Rules { /// trying to access the source files (`source_path`), or creating links /// in the output (`path`). pub def_paths: BTreeMap, + /// Set of rule name prefixes that have more specific rules within. + /// + /// For example, `asm.ts-args` is an interior prefix of `asm.ts-args.syntax`. + pub interior_prefixes: HashSet, } impl Spec { @@ -58,6 +62,12 @@ impl Spec { eprintln!("warning: {message}"); } } + let mut parts: Vec<_> = rule_id.split('.').collect(); + while !parts.is_empty() { + parts.pop(); + let prefix = parts.join("."); + rules.interior_prefixes.insert(prefix); + } }); } From 2c69550c04b9eec97a54da87070d75a7442b600b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 7 Oct 2024 16:26:02 -0700 Subject: [PATCH 123/189] More directly document the SPEC_RELATIVE environment variable --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a296a3b..ed97c7d 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,14 @@ SPEC_RELATIVE=0 mdbook build --open This will open a browser with a websocket live-link to automatically reload whenever the source is updated. -The `SPEC_RELATIVE=0` environment variable makes links to the standard library go to instead of being relative, which is useful when viewing locally since you normally don't have a copy of the standard library. - You can also use mdbook's live webserver option, which will automatically rebuild the book and reload your web browser whenever a source file is modified: ```sh SPEC_RELATIVE=0 mdbook serve --open ``` + +### `SPEC_RELATIVE` + +The `SPEC_RELATIVE=0` environment variable makes links to the standard library go to instead of being relative, which is useful when viewing locally since you normally don't have a copy of the standard library. + +The published site at (or local docs using `rustup doc`) does not set this, which means it will use relative links which supports offline viewing and links to the correct version (for example, links in will stay within the 1.81.0 directory). From 52746694d6cb10d1fe8a6ebcd220098f72e075e0 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 7 Oct 2024 16:26:59 -0700 Subject: [PATCH 124/189] Document SPEC_DENY_WARNINGS --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ed97c7d..af6310a 100644 --- a/README.md +++ b/README.md @@ -77,3 +77,7 @@ SPEC_RELATIVE=0 mdbook serve --open The `SPEC_RELATIVE=0` environment variable makes links to the standard library go to instead of being relative, which is useful when viewing locally since you normally don't have a copy of the standard library. The published site at (or local docs using `rustup doc`) does not set this, which means it will use relative links which supports offline viewing and links to the correct version (for example, links in will stay within the 1.81.0 directory). + +### `SPEC_DENY_WARNINGS` + +The `SPEC_DENY_WARNINGS=1` environment variable will turn all warnings generated by `mdbook-spec` to errors. This is used in CI to ensure that there aren't any problems with the book content. From 4e9227c4daf542a6d9580e465ae322ac629b5e5a Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 7 Oct 2024 16:37:35 -0700 Subject: [PATCH 125/189] Add test linking This adds the ability to link rust-lang/rust tests to reference rule annotations. Rules now have a link that pops up a list of tests that are associated with that rule. Additionally, there is a new appendix that lists the number of rules in each chapter, how many tests are associated, and various summaries. This requires a local checkout of rust-lang/rust which is pointed to by the `SPEC_RUST_ROOT` environment variable. --- .github/workflows/main.yml | 14 ++- README.md | 4 + book.toml | 1 + docs/authoring.md | 12 ++ mdbook-spec/Cargo.lock | 31 +++++- mdbook-spec/Cargo.toml | 1 + mdbook-spec/src/lib.rs | 60 +++++++++- mdbook-spec/src/rules.rs | 26 ++++- mdbook-spec/src/test_links.rs | 203 ++++++++++++++++++++++++++++++++++ src/SUMMARY.md | 1 + src/test-summary.md | 5 + theme/reference.css | 30 +++++ theme/reference.js | 24 ++++ 13 files changed, 403 insertions(+), 9 deletions(-) create mode 100644 mdbook-spec/src/test_links.rs create mode 100644 src/test-summary.md create mode 100644 theme/reference.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ccb3d0c..0c2b9b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,6 +35,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - name: Checkout rust-lang/rust + uses: actions/checkout@master + with: + repository: rust-lang/rust + path: rust - name: Update rustup run: rustup self update - name: Install Rust @@ -52,16 +57,17 @@ jobs: rustup --version rustc -Vv mdbook --version - - name: Verify the book builds - env: - SPEC_DENY_WARNINGS: 1 - run: mdbook build - name: Style checks working-directory: style-check run: cargo run --locked -- ../src - name: Style fmt working-directory: style-check run: cargo fmt --check + - name: Verify the book builds + env: + SPEC_DENY_WARNINGS: 1 + SPEC_RUST_ROOT: ${{ github.workspace }}/rust + run: mdbook build - name: Check for broken links run: | curl -sSLo linkcheck.sh \ diff --git a/README.md b/README.md index af6310a..0c7f3c4 100644 --- a/README.md +++ b/README.md @@ -81,3 +81,7 @@ The published site at (or local docs usin ### `SPEC_DENY_WARNINGS` The `SPEC_DENY_WARNINGS=1` environment variable will turn all warnings generated by `mdbook-spec` to errors. This is used in CI to ensure that there aren't any problems with the book content. + +### `SPEC_RUST_ROOT` + +The `SPEC_RUST_ROOT` can be used to point to the directory of a checkout of . This is used by the test-linking feature so that it can find tests linked to reference rules. If this is not set, then the tests won't be linked. diff --git a/book.toml b/book.toml index 404b8cc..18a9972 100644 --- a/book.toml +++ b/book.toml @@ -5,6 +5,7 @@ author = "The Rust Project Developers" [output.html] additional-css = ["theme/reference.css"] +additional-js = ["theme/reference.js"] git-repository-url = "https://github.com/rust-lang/reference/" edit-url-template = "https://github.com/rust-lang/reference/edit/master/{path}" smart-punctuation = true diff --git a/docs/authoring.md b/docs/authoring.md index cd5eaa7..fa32fc2 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -99,6 +99,18 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo * Target specific admonitions should typically be named by the least specific target property to which they apply (e.g. if a rule affects all x86 CPUs, the rule name should include `x86` rather than separately listing `i586`, `i686` and `x86_64`, and if a rule applies to all ELF platforms, it should be named `elf` rather than listing every ELF OS). * Use an appropriately descriptive, but short, name if the language does not provide one. +#### Test rule annotations + +Tests in can be linked to rules in the reference. The rule will include a link to the tests, and there is also an appendix which tracks how the rules are currently linked. + +Tests in the `tests` directory can be annotated with the `//@ reference: x.y.z` header to link it to a rule. The header can be specified multiple times if a single file covers multiple rules. + +You *should* when possible make sure every rule has a test associated with it. This is beneficial for reviewers to see the behavior and readers who may want to see examples of particular behaviors. When adding new rules, you should wait until the reference side is approved before submitting a PR to `rust-lang/rust` (to avoid churn if we decide on different names). + +Prefixed rule names should not be used in tests. That is, do not use something like `asm.rules` when there are specific rules like `asm.rules.reg-not-input`. + +We are not expecting 100% coverage at any time. Although it would be nice, it is unrealistic due to the sequence things are developed, and resources available. + ### Standard library links You should link to the standard library without specifying a URL in a fashion similar to [rustdoc intra-doc links][intra]. Some examples: diff --git a/mdbook-spec/Cargo.lock b/mdbook-spec/Cargo.lock index ff835b4..b101e14 100644 --- a/mdbook-spec/Cargo.lock +++ b/mdbook-spec/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -412,6 +412,7 @@ dependencies = [ "semver", "serde_json", "tempfile", + "walkdir", ] [[package]] @@ -597,6 +598,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "semver" version = "1.0.23" @@ -764,6 +774,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -834,6 +854,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/mdbook-spec/Cargo.toml b/mdbook-spec/Cargo.toml index 703322c..c9a6e31 100644 --- a/mdbook-spec/Cargo.toml +++ b/mdbook-spec/Cargo.toml @@ -19,3 +19,4 @@ regex = "1.9.4" semver = "1.0.21" serde_json = "1.0.113" tempfile = "3.10.1" +walkdir = "2.5.0" diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index add3b25..e559350 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -1,7 +1,7 @@ #![deny(rust_2018_idioms, unused_lifetimes)] use crate::rules::Rules; -use anyhow::Result; +use anyhow::{bail, Context, Result}; use mdbook::book::{Book, Chapter}; use mdbook::errors::Error; use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext}; @@ -10,9 +10,11 @@ use once_cell::sync::Lazy; use regex::{Captures, Regex}; use semver::{Version, VersionReq}; use std::io; +use std::path::PathBuf; mod rules; mod std_links; +mod test_links; /// The Regex for the syntax for blockquotes that have a specific CSS class, /// like `> [!WARNING]`. @@ -47,12 +49,37 @@ pub struct Spec { /// Whether or not warnings should be errors (set by SPEC_DENY_WARNINGS /// environment variable). deny_warnings: bool, + /// Path to the rust-lang/rust git repository (set by SPEC_RUST_ROOT + /// environment variable). + rust_root: Option, + /// The git ref that can be used in a URL to the rust-lang/rust repository. + git_ref: String, } impl Spec { fn new() -> Result { let deny_warnings = std::env::var("SPEC_DENY_WARNINGS").as_deref() == Ok("1"); - Ok(Spec { deny_warnings }) + let rust_root = std::env::var_os("SPEC_RUST_ROOT").map(PathBuf::from); + if deny_warnings && rust_root.is_none() { + bail!("SPEC_RUST_ROOT environment variable must be set"); + } + let git_ref = match git_ref(&rust_root) { + Ok(s) => s, + Err(e) => { + if deny_warnings { + eprintln!("error: {e:?}"); + std::process::exit(1); + } else { + eprintln!("warning: {e:?}"); + "master".into() + } + } + }; + Ok(Spec { + deny_warnings, + rust_root, + git_ref, + }) } /// Generates link references to all rules on all pages, so you can easily @@ -115,6 +142,28 @@ fn to_initial_case(s: &str) -> String { format!("{first}{rest}") } +/// Determines the git ref used for linking to a particular branch/tag in GitHub. +fn git_ref(rust_root: &Option) -> Result { + let Some(rust_root) = rust_root else { + return Ok("master".into()); + }; + let channel = std::fs::read_to_string(rust_root.join("src/ci/channel")) + .context("failed to read src/ci/channel")?; + let git_ref = match channel.trim() { + // nightly/beta are branches, not stable references. Should be ok + // because we're not expecting those channels to be long-lived. + "nightly" => "master".into(), + "beta" => "beta".into(), + "stable" => { + let version = std::fs::read_to_string(rust_root.join("src/version")) + .context("|| failed to read src/version")?; + version.trim().into() + } + ch => bail!("unknown channel {ch}"), + }; + Ok(git_ref) +} + impl Preprocessor for Spec { fn name(&self) -> &str { "spec" @@ -122,6 +171,8 @@ impl Preprocessor for Spec { fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result { let rules = self.collect_rules(&book); + let tests = self.collect_tests(&rules); + let summary_table = test_links::make_summary_table(&book, &tests, &rules); book.for_each_mut(|item| { let BookItem::Chapter(ch) = item else { @@ -132,7 +183,10 @@ impl Preprocessor for Spec { } ch.content = self.admonitions(&ch); ch.content = self.auto_link_references(&ch, &rules); - ch.content = self.render_rule_definitions(&ch.content); + ch.content = self.render_rule_definitions(&ch.content, &tests); + if ch.name == "Test summary" { + ch.content = ch.content.replace("{{summary-table}}", &summary_table); + } }); // Final pass will resolve everything as a std link (or error if the diff --git a/mdbook-spec/src/rules.rs b/mdbook-spec/src/rules.rs index ac402b8..b477ab7 100644 --- a/mdbook-spec/src/rules.rs +++ b/mdbook-spec/src/rules.rs @@ -1,11 +1,13 @@ //! Handling for rule identifiers. +use crate::test_links::RuleToTests; use crate::Spec; use mdbook::book::Book; use mdbook::BookItem; use once_cell::sync::Lazy; use regex::{Captures, Regex}; use std::collections::{BTreeMap, HashSet}; +use std::fmt::Write; use std::path::PathBuf; /// The Regex for rules like `r[foo]`. @@ -76,13 +78,35 @@ impl Spec { /// Converts lines that start with `r[…]` into a "rule" which has special /// styling and can be linked to. - pub fn render_rule_definitions(&self, content: &str) -> String { + pub fn render_rule_definitions(&self, content: &str, tests: &RuleToTests) -> String { RULE_RE .replace_all(content, |caps: &Captures<'_>| { let rule_id = &caps[1]; + let mut test_html = String::new(); + if let Some(tests) = tests.get(rule_id) { + test_html = format!( + "\n\ +     \ + Tests\n\ +
    \n\ + Tests with this rule: +
      "); + for test in tests { + writeln!( + test_html, + "
    • {test_path}
    • ", + test_path = test.path, + git_ref = self.git_ref + ) + .unwrap(); + } + + test_html.push_str("
    "); + } format!( "
    \ [{rule_id}]\ + {test_html}\
    \n" ) }) diff --git a/mdbook-spec/src/test_links.rs b/mdbook-spec/src/test_links.rs new file mode 100644 index 0000000..8f847d5 --- /dev/null +++ b/mdbook-spec/src/test_links.rs @@ -0,0 +1,203 @@ +//! Handling for linking tests in rust's testsuite to rule identifiers. + +use crate::{Rules, Spec}; +use mdbook::book::{Book, BookItem}; +use std::collections::HashMap; +use std::fmt::Write; +use std::path::PathBuf; +use walkdir::WalkDir; + +/// Mapping of rule identifier to the tests that include that identifier. +pub type RuleToTests = HashMap>; +/// A test in rustc's test suite. +pub struct Test { + pub path: String, +} + +const TABLE_START: &str = " + + + + + + + + +"; + +/// Generates an HTML table summarizing the coverage of the testsuite. +pub fn make_summary_table(book: &Book, tests: &RuleToTests, rules: &Rules) -> String { + let ch_to_rules = invert_rule_map(rules); + + let mut table = String::from(TABLE_START); + let mut total_rules = 0; + let mut total_tests = 0; + let mut total_uncovered = 0; + + for (item_index, item) in book.iter().enumerate() { + let BookItem::Chapter(ch) = item else { + continue; + }; + let Some(ch_path) = &ch.path else { + continue; + }; + let level = ch + .number + .as_ref() + .map(|ch| ch.len() - 1) + .unwrap_or_default() as u32; + // Note: This path assumes that the summary chapter is in the root of + // the book. If instead it is in a subdirectory, then this needs to + // include relative `../` as needed. + let html_path = ch_path + .with_extension("html") + .to_str() + .unwrap() + .replace('\\', "/"); + let number = ch + .number + .as_ref() + .map(|n| n.to_string()) + .unwrap_or_default(); + let mut num_rules = 0; + let mut num_tests_str = String::from(""); + let mut uncovered_str = String::from(""); + let mut coverage_str = String::from(""); + if let Some(rules) = ch_to_rules.get(ch_path) { + num_rules = rules.len(); + total_rules += num_rules; + let num_tests = rules + .iter() + .map(|rule| tests.get(rule).map(|ts| ts.len()).unwrap_or_default()) + .sum::(); + total_tests += num_tests; + num_tests_str = num_tests.to_string(); + let uncovered_rules: Vec<_> = rules + .iter() + .filter(|rule| !tests.contains_key(rule.as_str())) + .collect(); + let uncovered = uncovered_rules.len(); + total_uncovered += uncovered; + coverage_str = fmt_pct(uncovered, num_rules); + if uncovered == 0 { + uncovered_str = String::from("0"); + } else { + uncovered_str = format!( + "
    \n\ + \ + {uncovered}\n\ +
    \n\ + Uncovered rules +
      "); + for uncovered_rule in uncovered_rules { + writeln!( + uncovered_str, + "
    • {uncovered_rule}
    • " + ) + .unwrap(); + } + uncovered_str.push_str("
    "); + } + } + let indent = " ".repeat(level as usize * 6); + + writeln!( + table, + "
    \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + ", + name = ch.name, + ) + .unwrap(); + } + + let total_coverage = fmt_pct(total_uncovered, total_rules); + writeln!( + table, + "\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + " + ) + .unwrap(); + table.push_str("
    RulesTestsUncovered RulesCoverage
    {indent}{number} {name}{num_rules}{num_tests_str}{uncovered_str}{coverage_str}
    Total:{total_rules}{total_tests}{total_uncovered}{total_coverage}
    \n"); + table +} + +/// Formats a float as a percentage string. +fn fmt_pct(uncovered: usize, total: usize) -> String { + let pct = ((total - uncovered) as f32 / total as f32) * 100.0; + // Round up to tenths of a percent. + let x = (pct * 10.0).ceil() / 10.0; + format!("{x:.1}%") +} + +/// Inverts the rule map so that it is chapter path to set of rules in that +/// chapter. +fn invert_rule_map(rules: &Rules) -> HashMap> { + let mut map: HashMap> = HashMap::new(); + for (rule, (_, path)) in &rules.def_paths { + map.entry(path.clone()).or_default().push(rule.clone()); + } + for value in map.values_mut() { + value.sort(); + } + map +} + +impl Spec { + /// Scans all tests in rust-lang/rust, and creates a mapping of a rule + /// identifier to the set of tests that include that identifier. + pub fn collect_tests(&self, rules: &Rules) -> RuleToTests { + let mut map = HashMap::new(); + let Some(rust_root) = &self.rust_root else { + return map; + }; + for entry in WalkDir::new(rust_root.join("tests")) { + let entry = entry.unwrap(); + let path = entry.path(); + let relative = path.strip_prefix(rust_root).unwrap_or_else(|_| { + panic!("expected root {rust_root:?} to be a prefix of {path:?}") + }); + if path.extension().unwrap_or_default() == "rs" { + let contents = std::fs::read_to_string(path).unwrap(); + for line in contents.lines() { + if let Some(id) = line.strip_prefix("//@ reference: ") { + if rules.interior_prefixes.contains(id) { + let instead: Vec<_> = rules + .def_paths + .keys() + .filter(|key| key.starts_with(&format!("{id}."))) + .collect(); + eprintln!( + "info: Interior prefix rule {id} found in {path:?}\n \ + Tests should not be annotated with prefixed rule names.\n \ + Use the rules from {instead:?} instead." + ); + } else if !rules.def_paths.contains_key(id) { + eprintln!( + "info: Orphaned rule identifier {id} found in {path:?}\n \ + Please update the test to use an existing rule name." + ); + } + let test = Test { + path: relative.to_str().unwrap().replace('\\', "/"), + }; + map.entry(id.to_string()).or_default().push(test); + } + } + } + } + for tests in map.values_mut() { + tests.sort_by(|a, b| a.path.cmp(&b.path)); + } + map + } +} diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 2b17bf4..91f343b 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -132,4 +132,5 @@ - [Appendices](appendices.md) - [Macro Follow-Set Ambiguity Formal Specification](macro-ambiguity.md) - [Influences](influences.md) + - [Test summary](test-summary.md) - [Glossary](glossary.md) diff --git a/src/test-summary.md b/src/test-summary.md new file mode 100644 index 0000000..e4e3e74 --- /dev/null +++ b/src/test-summary.md @@ -0,0 +1,5 @@ +# Test summary + +The following is a summary of the total tests that are linked to individual rule identifiers within the reference. + +{{summary-table}} diff --git a/theme/reference.css b/theme/reference.css index cbc7aca..58be918 100644 --- a/theme/reference.css +++ b/theme/reference.css @@ -200,3 +200,33 @@ dfn { .history > blockquote { background: #f7c0eb; } + +/* Provides a anchor container for positioning popups. */ +.popup-container { + position: relative; +} +/* In the test summary page, a convenience class for toggling visibility. */ +.popup-hidden { + display: none; +} +/* In the test summary page, the styling for the uncovered rule popup. */ +.uncovered-rules-popup { + position: absolute; + left: -250px; + width: 400px; + background: var(--bg); + border-radius: 4px; + border: 1px solid; + z-index: 1000; + padding: 1rem; +} + +/* The popup that shows when viewing tests for a specific rule. */ +.tests-popup { + color: var(--fg); + background: var(--bg); + border-radius: 4px; + border: 1px solid; + z-index: 1000; + padding: 1rem; +} diff --git a/theme/reference.js b/theme/reference.js new file mode 100644 index 0000000..44a2370 --- /dev/null +++ b/theme/reference.js @@ -0,0 +1,24 @@ +/* On the test summary page, toggles the popup for the uncovered tests. */ +function spec_toggle_uncovered(item_index) { + let el = document.getElementById(`uncovered-${item_index}`); + const currently_hidden = el.classList.contains('popup-hidden'); + const all = document.querySelectorAll('.uncovered-rules-popup'); + all.forEach(element => { + element.classList.add('popup-hidden'); + }); + if (currently_hidden) { + el.classList.remove('popup-hidden'); + } +} + +function spec_toggle_tests(rule_id) { + let el = document.getElementById(`tests-${rule_id}`); + const currently_hidden = el.classList.contains('popup-hidden'); + const all = document.querySelectorAll('.tests-popup'); + all.forEach(element => { + element.classList.add('popup-hidden'); + }); + if (currently_hidden) { + el.classList.remove('popup-hidden'); + } +} From 99c65ecb89375ce5b37fa885dc83364b684de7dd Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 9 Oct 2024 19:10:11 -0700 Subject: [PATCH 126/189] Link the appendix --- docs/authoring.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/authoring.md b/docs/authoring.md index fa32fc2..5c068c6 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -101,7 +101,7 @@ When assigning rules to new paragraphs, or when modifying rule names, use the fo #### Test rule annotations -Tests in can be linked to rules in the reference. The rule will include a link to the tests, and there is also an appendix which tracks how the rules are currently linked. +Tests in can be linked to rules in the reference. The rule will include a link to the tests, and there is also an [appendix] which tracks how the rules are currently linked. Tests in the `tests` directory can be annotated with the `//@ reference: x.y.z` header to link it to a rule. The header can be specified multiple times if a single file covers multiple rules. @@ -111,6 +111,8 @@ Prefixed rule names should not be used in tests. That is, do not use something l We are not expecting 100% coverage at any time. Although it would be nice, it is unrealistic due to the sequence things are developed, and resources available. +[appendix]: https://doc.rust-lang.org/nightly/reference/test-summary.html + ### Standard library links You should link to the standard library without specifying a URL in a fashion similar to [rustdoc intra-doc links][intra]. Some examples: From 167ac4e6db2002269e45fa6a5eae9f56a88002d7 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 9 Oct 2024 19:14:08 -0700 Subject: [PATCH 127/189] Add a little clarity around who is responsible for what --- docs/authoring.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/authoring.md b/docs/authoring.md index 5c068c6..29a476c 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -105,7 +105,9 @@ Tests in can be linked to rules in the refer Tests in the `tests` directory can be annotated with the `//@ reference: x.y.z` header to link it to a rule. The header can be specified multiple times if a single file covers multiple rules. -You *should* when possible make sure every rule has a test associated with it. This is beneficial for reviewers to see the behavior and readers who may want to see examples of particular behaviors. When adding new rules, you should wait until the reference side is approved before submitting a PR to `rust-lang/rust` (to avoid churn if we decide on different names). +Compiler developers are not expected to add `reference` annotations to tests. However, if they do want to help, their cooperation is very welcome. Reference authors and editors are responsible for making sure every rule has a test associated with it. + +The tests are beneficial for reviewers to see the behavior of a rule. It is also a benefit to readers who may want to see examples of particular behaviors. When adding new rules, you should wait until the reference side is approved before submitting a PR to `rust-lang/rust` (to avoid churn if we decide on different names). Prefixed rule names should not be used in tests. That is, do not use something like `asm.rules` when there are specific rules like `asm.rules.reg-not-input`. From 1bafe5b6b93e6de6231214618fd3065ebf93578e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 12 Oct 2024 08:22:16 -0700 Subject: [PATCH 128/189] CI: Update preview job to include test links --- .github/workflows/main.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0c2b9b8..718b54f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -109,6 +109,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - name: Checkout rust-lang/rust + uses: actions/checkout@master + with: + repository: rust-lang/rust + path: rust - name: Update rustup run: rustup self update - name: Install Rust @@ -123,7 +128,8 @@ jobs: echo "$(pwd)/bin" >> $GITHUB_PATH - name: Build the book env: - SPEC_RELATIVE: 0 + SPEC_RELATIVE: 0 + SPEC_RUST_ROOT: ${{ github.workspace }}/rust run: mdbook build --dest-dir dist/preview-${{ github.event.pull_request.number }} - name: Upload artifact uses: actions/upload-artifact@v4 From 0515d0b0b1d5029a5f4a9e574fbf9f910bec18d4 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 18 Oct 2024 18:11:18 +0200 Subject: [PATCH 129/189] Allow `deny` inside `forbid` as a no-op --- src/attributes/diagnostics.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 34dab59..6d21a5a 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -43,8 +43,9 @@ pub mod m1 { ``` Lint attributes can override the level specified from a previous attribute, as -long as the level does not attempt to change a forbidden lint. Previous -attributes are those from a higher level in the syntax tree, or from a +long as the level does not attempt to change a forbidden lint +(except for `deny`, which is allowed inside a `forbid` context, but ignored). +Previous attributes are those from a higher level in the syntax tree, or from a previous attribute on the same entity as listed in left-to-right source order. This example shows how one can use `allow` and `warn` to toggle a particular From 540ac90e669ebc89c2eaf0d93f050494f0126faa Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 12:14:52 -0400 Subject: [PATCH 130/189] Add identifier syntax to attributes.md --- src/attributes.md | 60 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index f3ca917..794f875 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -1,6 +1,10 @@ {{#include attributes-redirect.html}} # Attributes +r[attributes] + + +r[attributes.syntax] > **Syntax**\ > _InnerAttribute_ :\ >    `#` `!` `[` _Attr_ `]` @@ -16,20 +20,24 @@ >       [_DelimTokenTree_]\ >    | `=` [_Expression_] +r[attributes.general] An _attribute_ is a general, free-form metadatum that is interpreted according to name, convention, language, and compiler version. Attributes are modeled on Attributes in [ECMA-335], with the syntax coming from [ECMA-334] \(C#). +r[attributes.inner] _Inner attributes_, written with a bang (`!`) after the hash (`#`), apply to the item that the attribute is declared within. _Outer attributes_, written without the bang after the hash, apply to the thing that follows the attribute. +r[attributes.input] The attribute consists of a path to the attribute, followed by an optional delimited token tree whose interpretation is defined by the attribute. Attributes other than macro attributes also allow the input to be an equals sign (`=`) followed by an expression. See the [meta item syntax](#meta-item-attribute-syntax) below for more details. +r[attributes.safety] An attribute may be unsafe to apply. To avoid undefined behavior when using these attributes, certain obligations that cannot be checked by the compiler must be met. To assert these have been, the attribute is wrapped in @@ -41,15 +49,15 @@ The following attributes are unsafe: * [`link_section`] * [`no_mangle`] +r[attributes.kind] Attributes can be classified into the following kinds: - * [Built-in attributes] * [Macro attributes][attribute macros] * [Derive macro helper attributes] * [Tool attributes](#tool-attributes) +r[attributes.application] Attributes may be applied to many things in the language: - * All [item declarations] accept outer attributes while [external blocks], [functions], [implementations], and [modules] accept inner attributes. * Most [statements] accept outer attributes (see [Expression Attributes] for @@ -100,9 +108,14 @@ fn some_unused_variables() { ## Meta Item Attribute Syntax +r[attributes.meta] + + +r[attributes.meta.general] A "meta item" is the syntax used for the _Attr_ rule by most [built-in attributes]. It has the following grammar: +r[attributes.meta.syntax] > **Syntax**\ > _MetaItem_ :\ >       [_SimplePath_]\ @@ -116,10 +129,12 @@ attributes]. It has the following grammar: >       _MetaItem_\ >    | [_Expression_] +r[attributes.meta.literal-expr] Expressions in meta items must macro-expand to literal expressions, which must not include integer or float type suffixes. Expressions which are not literal expressions will be syntactically accepted (and can be passed to proc-macros), but will be rejected after parsing. +r[attributes.meta.order] Note that if the attribute appears within another macro, it will be expanded after that outer macro. For example, the following code will expand the `Serialize` proc-macro first, which must preserve the `include_str!` call in @@ -133,6 +148,7 @@ struct Foo { } ``` +r[attributes.meta.order-macro] Additionally, macros in attributes will be expanded only after all other attributes applied to the item: ```rust ignore @@ -143,6 +159,7 @@ Additionally, macros in attributes will be expanded only after all other attribu fn foo() {} ``` +r[attributes.meta.builtin] Various built-in attributes use different subsets of the meta item syntax to specify their inputs. The following grammar rules show some commonly used forms: @@ -175,6 +192,9 @@ _MetaListNameValueStr_ | `link(name = "CoreFoundation", kind = "framework")` ## Active and inert attributes +r[attributes.activity] + +r[attributes.activity.general] An attribute is either active or inert. During attribute processing, *active attributes* remove themselves from the thing they are on while *inert attributes* stay on. @@ -185,15 +205,20 @@ active. All other attributes are inert. ## Tool attributes +r[attributes.tool] + +r[attributes.tool.general] The compiler may allow attributes for external tools where each tool resides in its own module in the [tool prelude]. The first segment of the attribute path is the name of the tool, with one or more additional segments whose interpretation is up to the tool. +r[attributes.tool.ignored] When a tool is not in use, the tool's attributes are accepted without a warning. When the tool is in use, the tool is responsible for processing and interpretation of its attributes. +r[attributes.tool.prelude] Tool attributes are not available if the [`no_implicit_prelude`] attribute is used. @@ -213,19 +238,28 @@ pub fn f() {} ## Built-in attributes index +r[attributes.builtin] + The following is an index of all built-in attributes. +r[attributes.builtin.cfg] - Conditional compilation - [`cfg`] --- Controls conditional compilation. - [`cfg_attr`] --- Conditionally includes attributes. + +r[attributes.builtin.testing] - Testing - [`test`] --- Marks a function as a test. - [`ignore`] --- Disables a test function. - [`should_panic`] --- Indicates a test should generate a panic. + +r[attributes.builtin.derive] - Derive - [`derive`] --- Automatic trait implementations. - [`automatically_derived`] --- Marker for implementations created by `derive`. + +r[attributes.builtin.macros] - Macros - [`macro_export`] --- Exports a `macro_rules` macro for cross-crate usage. - [`macro_use`] --- Expands macro visibility, or imports macros from other @@ -233,12 +267,16 @@ The following is an index of all built-in attributes. - [`proc_macro`] --- Defines a function-like macro. - [`proc_macro_derive`] --- Defines a derive macro. - [`proc_macro_attribute`] --- Defines an attribute macro. + +r[attributes.builtin.diagnostic] - Diagnostics - [`allow`], [`expect`], [`warn`], [`deny`], [`forbid`] --- Alters the default lint level. - [`deprecated`] --- Generates deprecation notices. - [`must_use`] --- Generates a lint for unused values. - [`diagnostic::on_unimplemented`] --- Hints the compiler to emit a certain error message if a trait is not implemented. + +r[attributes.builtin.linkage] - ABI, linking, symbols, and FFI - [`link`] --- Specifies a native library to link with an `extern` block. - [`link_name`] --- Specifies the name of the symbol for functions or statics @@ -257,6 +295,8 @@ The following is an index of all built-in attributes. - [`used`] --- Forces the compiler to keep a static item in the output object file. - [`crate_name`] --- Specifies the crate name. + +r[attributes.builtin.codegen] - Code generation - [`inline`] --- Hint to inline code. - [`cold`] --- Hint that a function is unlikely to be called. @@ -264,28 +304,44 @@ The following is an index of all built-in attributes. - [`target_feature`] --- Configure platform-specific code generation. - [`track_caller`] - Pass the parent call location to `std::panic::Location::caller()`. - [`instruction_set`] - Specify the instruction set used to generate a functions code + +r[attributes.builtin.doc] - Documentation - `doc` --- Specifies documentation. See [The Rustdoc Book] for more information. [Doc comments] are transformed into `doc` attributes. + +r[attributes.builtin.prelude] - Preludes - [`no_std`] --- Removes std from the prelude. - [`no_implicit_prelude`] --- Disables prelude lookups within a module. + +r[attributes.builtin.module] - Modules - [`path`] --- Specifies the filename for a module. + +r[attributes.builtin.limits] - Limits - [`recursion_limit`] --- Sets the maximum recursion limit for certain compile-time operations. - [`type_length_limit`] --- Sets the maximum size of a polymorphic type. + +r[attributes.builtin.rt] - Runtime - [`panic_handler`] --- Sets the function to handle panics. - [`global_allocator`] --- Sets the global memory allocator. - [`windows_subsystem`] --- Specifies the windows subsystem to link with. + +r[attributes.builtin.unstable] - Features - `feature` --- Used to enable unstable or experimental compiler features. See [The Unstable Book] for features implemented in `rustc`. + +r[attributes.builtin.typesystem] - Type System - [`non_exhaustive`] --- Indicate that a type will have more fields/variants added in future. + +r[attributes.builtin.debugging] - Debugger - [`debugger_visualizer`] --- Embeds a file that specifies debugger output for a type. - [`collapse_debuginfo`] --- Controls how macro invocations are encoded in debuginfo. From 6e9117c5403f3093a3542408d35441a33bdab32e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 12:15:04 -0400 Subject: [PATCH 131/189] Add identifier syntax to attributes.codegen --- src/attributes/codegen.md | 61 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index f30c296..0e170ce 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -1,13 +1,19 @@ # Code generation attributes +r[attributes.codegen] + The following [attributes] are used for controlling code generation. ## Optimization hints +r[attributes.codegen.hint] + +r[attributes.codegen.hint.cold-inline] The `cold` and `inline` [attributes] give suggestions to generate code in a way that may be faster than what it would do without the hint. The attributes are only hints, and may be ignored. +r[attributes.codegen.hint.usage] Both attributes can be used on [functions]. When applied to a function in a [trait], they apply only to that function when used as a default function for a trait implementation and not to all trait implementations. The attributes @@ -15,6 +21,9 @@ have no effect on a trait function without a body. ### The `inline` attribute +r[attributes.codgen.inline] + +r[attributes.codegen.inline.general] The *`inline` [attribute]* suggests that a copy of the attributed function should be placed in the caller, rather than generating code to call the function where it is defined. @@ -23,6 +32,7 @@ function where it is defined. > internal heuristics. Incorrectly inlining functions can make the program > slower, so this attribute should be used with care. +r[attributes.codegen.inline.modes] There are three ways to use the inline attribute: * `#[inline]` *suggests* performing an inline expansion. @@ -36,17 +46,25 @@ There are three ways to use the inline attribute: ### The `cold` attribute +r[attribute.codegen.cold] + The *`cold` [attribute]* suggests that the attributed function is unlikely to be called. ## The `no_builtins` attribute +r[attributes.codegen.no_builtins] + The *`no_builtins` [attribute]* may be applied at the crate level to disable optimizing certain code patterns to invocations of library functions that are assumed to exist. ## The `target_feature` attribute +r[attributes.codegen.target_feature] + + +r[attributes.codegen.target_feature.general] The *`target_feature` [attribute]* may be applied to a function to enable code generation of that function for specific platform architecture features. It uses the [_MetaListNameValueStr_] syntax with a single key of @@ -58,24 +76,31 @@ features. It uses the [_MetaListNameValueStr_] syntax with a single key of unsafe fn foo_avx2() {} ``` +r[attributes.codegen.target_features.arch] Each [target architecture] has a set of features that may be enabled. It is an error to specify a feature for a target architecture that the crate is not being compiled for. +r[attributes.codegen.target_features.precondition] It is [undefined behavior] to call a function that is compiled with a feature that is not supported on the current platform the code is running on, *except* if the platform explicitly documents this to be safe. +r[attributes.codegen.target_features.restriction] Functions marked with `target_feature` are not inlined into a context that does not support the given features. The `#[inline(always)]` attribute may not be used with a `target_feature` attribute. ### Available features +r[attributes.codegen.target_features.availability] + The following is a list of the available feature names. #### `x86` or `x86_64` +r[attributes.codegen.target_features.x86] + Executing code with unsupported features is undefined behavior on this platform. Hence this platform requires that `#[target_feature]` is only applied to [`unsafe` functions][unsafe function]. @@ -143,6 +168,8 @@ Feature | Implicitly Enables | Description #### `aarch64` +r[attributes.codegen.target_feature.aarch64] + This platform requires that `#[target_feature]` is only applied to [`unsafe` functions][unsafe function]. @@ -206,6 +233,8 @@ Feature | Implicitly Enables | Feature Name #### `riscv32` or `riscv64` +r[attributes.codegen.target_feature.riscv] + This platform requires that `#[target_feature]` is only applied to [`unsafe` functions][unsafe function]. @@ -266,6 +295,8 @@ Feature | Implicitly Enables | Description #### `wasm32` or `wasm64` +r[attributes.codegen.target_feature.wasm] + `#[target_feature]` may be used with both safe and [`unsafe` functions][unsafe function] on Wasm platforms. It is impossible to cause undefined behavior via the `#[target_feature]` attribute because @@ -293,11 +324,15 @@ Feature | Implicitly Enables | Description ### Additional information +r[attributes.codegen.target_feature.info] + +r[attributes.codegen.target_feature.remark-cfg] See the [`target_feature` conditional compilation option] for selectively enabling or disabling compilation of code based on compile-time settings. Note 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. @@ -308,11 +343,17 @@ in the standard library for runtime feature detection on these platforms. ## The `track_caller` attribute +r[attributes.codegen.track_caller] + +r[attributes.codegen.track_caller.restriction] The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] -with the exception of the entry point `fn main`. When applied to functions and methods in -trait declarations, the attribute applies to all implementations. If the trait provides a +with the exception of the entry point `fn main`. + +r[attributes.codegen.track_caller.traits] +When applied to functions and methods in trait declarations, the attribute applies to all implementations. If the trait provides a default implementation with the attribute, then the attribute also applies to override implementations. +r[attributes.codegen.track_caller.extern] When applied to a function in an `extern` block the attribute must also be applied to any linked implementations, otherwise undefined behavior results. When applied to a function which is made available to an `extern` block, the declaration in the `extern` block must also have the attribute, @@ -320,6 +361,7 @@ otherwise undefined behavior results. ### Behavior +r[attributes.codegen.track_caller.behaviour] Applying the attribute to a function `f` allows code within `f` to get a hint of the [`Location`] of the "topmost" tracked call that led to `f`'s invocation. At the point of observation, an implementation behaves as if it walks up the stack from `f`'s frame to find the nearest frame of an @@ -399,8 +441,12 @@ And so on. ### Limitations +r[attributes.codegen.track_caller.limits] + +r[attributes.codegent.track_caller.hint] This information is a hint and implementations are not required to preserve it. +r[attributes.codegen.track_caller.decay] In particular, coercing a function with `#[track_caller]` to a function pointer creates a shim which appears to observers to have been called at the attributed function's definition site, losing actual caller information across virtual calls. A common example of this coercion is the creation of a @@ -431,18 +477,27 @@ trait object whose methods are attributed. ## The `instruction_set` attribute +r[attributes.codegen.instruction_set] + +r[attributes.codegen.instruction_set.restriction] The *`instruction_set` [attribute]* may be applied to a function to control which instruction set the function will be generated for. + +r[attributes.codegen.instruction_set.behaviour] This allows mixing more than one instruction set in a single program on CPU architectures that support it. + +r[attributes.codegen.instruction_set.syntax] It uses the [_MetaListPath_] syntax, and a path comprised of the architecture family name and instruction set name. [_MetaListPath_]: ../attributes.md#meta-item-attribute-syntax +r[attributes.codegen.instruction_set.target-limits] It is a compilation error to use the `instruction_set` attribute on a target that does not support it. ### On ARM -For the `ARMv4T` and `ARMv5te` architectures, the following are supported: +r[attributes.codegen.instruction_set.arm] +For the `ARMv4T` and `ARMv5te` architectures, the following are supported: * `arm::a32` --- Generate the function as A32 "ARM" code. * `arm::t32` --- Generate the function as T32 "Thumb" code. From 029898f70d6727b58bcc4cb5efa384fde745489f Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 12:15:15 -0400 Subject: [PATCH 132/189] Add identifier syntax to attributes.debugger --- src/attributes/debugger.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/attributes/debugger.md b/src/attributes/debugger.md index 21add01..44e05e8 100644 --- a/src/attributes/debugger.md +++ b/src/attributes/debugger.md @@ -1,20 +1,32 @@ # Debugger attributes +r[attributes.debugger] + The following [attributes] are used for enhancing the debugging experience when using third-party debuggers like GDB or WinDbg. ## The `debugger_visualizer` attribute +r[attributes.debugger.debugger_visualizer] + +r[attributes.debugger.debugger_visualizer.general] The *`debugger_visualizer` attribute* can be used to embed a debugger visualizer file into the debug information. This enables an improved debugger experience for displaying values in the debugger. + +r[attributes.debugger.debugger_visualizer.restriction] It uses the [_MetaListNameValueStr_] syntax to specify its inputs, and must be specified as a crate attribute. ### Using `debugger_visualizer` with Natvis +r[attributes.debugger.debugger_visualizer.natvis] + +r[attributes.debugger.debugger_visualizer.natvis-general] Natvis is an XML-based framework for Microsoft debuggers (such as Visual Studio and WinDbg) that uses declarative rules to customize the display of types. For detailed information on the Natvis format, refer to Microsoft's [Natvis documentation]. +r[attributes.debugger.debugger_visualizer.natvis-restrictions] This attribute only supports embedding Natvis files on `-windows-msvc` targets. +r[attributes.debugger.debugger_visualizer.natvis-path] The path to the Natvis file is specified with the `natvis_file` key, which is a path relative to the crate source file: @@ -72,6 +84,10 @@ When viewed under WinDbg, the `fancy_rect` variable would be shown as follows: ### Using `debugger_visualizer` with GDB +r[attributes.debugger.debugger_visualizer.gdb] + + +r[attributes.debugger.debugger_visualizer.gdb-pretty] GDB supports the use of a structured Python script, called a *pretty printer*, that describes how a type should be visualized in the debugger view. For detailed information on pretty printers, refer to GDB's [pretty printing documentation]. @@ -81,6 +97,7 @@ There are two ways to enable auto-loading embedded pretty printers: For more information, see GDB's [auto-loading documentation]. 1. Create a file named `gdbinit` under `$HOME/.config/gdb` (you may need to create the directory if it doesn't already exist). Add the following line to that file: `add-auto-load-safe-path path/to/binary`. +r[attributes.debugger.debugger_visualizer.gdb-path] These scripts are embedded using the `gdb_script_file` key, which is a path relative to the crate source file. @@ -142,16 +159,23 @@ When the crate's debug executable is passed into GDB[^rust-gdb], `print bob` wil ## The `collapse_debuginfo` attribute +r[attributes.debugger.collapse_debuginfo] + + +r[attributes.debugger.collapse_debuginfo.general] The *`collapse_debuginfo` [attribute]* controls whether code locations from a macro definition are collapsed into a single location associated with the macro's call site, when generating debuginfo for code calling this macro. +r[attributes.debugger.collapse_debuginfo.syntax] The attribute uses the [_MetaListIdents_] syntax to specify its inputs, and can only be applied to macro definitions. +r[attributes.debugger.collapse_debuginfo.options] Accepted options: - `#[collapse_debuginfo(yes)]` --- code locations in debuginfo are collapsed. - `#[collapse_debuginfo(no)]` --- code locations in debuginfo are not collapsed. - `#[collapse_debuginfo(external)]` --- code locations in debuginfo are collapsed only if the macro comes from a different crate. +r[attributes.debugger.collapse_debuginfo.default] The `external` behavior is the default for macros that don't have this attribute, unless they are built-in macros. For built-in macros the default is `yes`. From 4f62f7c202fb5ff6f48b3b97c88e6422afa4b92d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 12:16:29 -0400 Subject: [PATCH 133/189] Add identifier syntax to attributes.derive --- src/attributes/derive.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/attributes/derive.md b/src/attributes/derive.md index 44ce8c7..c8938f3 100644 --- a/src/attributes/derive.md +++ b/src/attributes/derive.md @@ -1,7 +1,14 @@ # Derive +r[attributes.derive] + + +r[attributes.derived.general] The *`derive` attribute* allows new [items] to be automatically generated for -data structures. It uses the [_MetaListPaths_] syntax to specify a list of +data structures. + +r[attributes.derive.syntax] +It uses the [_MetaListPaths_] syntax to specify a list of traits to implement or paths to [derive macros] to process. For example, the following will create an [`impl` item] for the @@ -27,10 +34,12 @@ impl PartialEq for Foo { } ``` +r[attributes.derive.proc-macro] You can implement `derive` for your own traits through [procedural macros]. ## The `automatically_derived` attribute +r[attributes.derive.automatically_derived] The *`automatically_derived` attribute* is automatically added to [implementations] created by the `derive` attribute for built-in traits. It has no direct effect, but it may be used by tools and diagnostic lints to From f906af5e5074ebf71632773355f054a9f6bedc71 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 12:30:17 -0400 Subject: [PATCH 134/189] Add identifier syntax to attributes.diagnostics --- src/attributes/diagnostics.md | 72 +++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 6d21a5a..d1dde2e 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -1,25 +1,41 @@ # Diagnostic attributes +r[attributes.diagnostics] + The following [attributes] are used for controlling or generating diagnostic messages during compilation. ## Lint check attributes +r[attributes.diagnostics.lints] + A lint check names a potentially undesirable coding pattern, such as -unreachable code or omitted documentation. The lint attributes `allow`, +unreachable code or omitted documentation. + +r[attributes.diagnostics.lints.level] +The lint attributes `allow`, `expect`, `warn`, `deny`, and `forbid` use the [_MetaListPaths_] syntax to specify a list of lint names to change the lint level for the entity to which the attribute applies. For any lint check `C`: +r[attributes.diagnostics.lints.allow] * `#[allow(C)]` overrides the check for `C` so that violations will go unreported. + +r[attributes.diagnostics.lints.expect] * `#[expect(C)]` indicates that lint `C` is expected to be emitted. The attribute will suppress the emission of `C` or issue a warning, if the expectation is unfulfilled. + +r[attributes.diagnostics.lints.warn] * `#[warn(C)]` warns about violations of `C` but continues compilation. + +r[attributes.diagnostics.lints.deny] * `#[deny(C)]` signals an error after encountering a violation of `C`, + +r[attributes.diagnostics.lints.forbid] * `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint level afterwards, @@ -42,6 +58,7 @@ pub mod m1 { } ``` +r[attributes.diagnostics.lints.override] Lint attributes can override the level specified from a previous attribute, as long as the level does not attempt to change a forbidden lint (except for `deny`, which is allowed inside a `forbid` context, but ignored). @@ -89,6 +106,7 @@ pub mod m3 { ### Lint Reasons +r[attributes.diagnostics.lints.reason] All lint attributes support an additional `reason` parameter, to give context why a certain attribute was added. This reason will be displayed as part of the lint message if the lint is emitted at the defined level. @@ -125,6 +143,9 @@ pub fn get_path() -> PathBuf { ### The `#[expect]` attribute +r[attributes.diagnostics.expect] + +r[attributes.diagnostics.expect.general] The `#[expect(C)]` attribute creates a lint expectation for lint `C`. The expectation will be fulfilled, if a `#[warn(C)]` attribute at the same location would result in a lint emission. If the expectation is unfulfilled, because @@ -150,6 +171,7 @@ fn main() { } ``` +r[attributes.lints.expect.fulfilment] The lint expectation is only fulfilled by lint emissions which have been suppressed by the `expect` attribute. If the lint level is modified in the scope with other level attributes like `allow` or `warn`, the lint emission will be handled accordingly and the @@ -179,6 +201,7 @@ fn select_song() { } ``` +r[attributes.diagnostics.expect.independent] If the `expect` attribute contains several lints, each one is expected separately. For a lint group it's enough if one lint inside the group has been emitted: @@ -207,6 +230,7 @@ pub fn another_example() { ### Lint groups +r[attributes.lints.groups] Lints may be organized into named groups so that the level of related lints can be adjusted together. Using a named group is equivalent to listing out the lints within that group. @@ -227,6 +251,7 @@ fn example() { } ``` +r[attributes.lints.warnings-group] There is a special group named "warnings" which includes all lints at the "warn" level. The "warnings" group ignores attribute order and applies to all lints that would otherwise warn within the entity. @@ -246,9 +271,13 @@ fn example_err() { ### Tool lint attributes +r[attributes.lints.tools] + +r[attributes.lints.tools.general] Tool lints allows using scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of certain tools. +r[attributes.lints.tools.activation] Tool lints only get checked when the associated tool is active. If a lint attribute, such as `allow`, references a nonexistent tool lint, the compiler will not warn about the nonexistent lint until you use the tool. @@ -276,10 +305,14 @@ fn foo() { ## The `deprecated` attribute +r[attributes.diagnostics.deprecated] + +r[attributes.diagnostics.deprecated.general] The *`deprecated` attribute* marks an item as deprecated. `rustc` will issue warnings on usage of `#[deprecated]` items. `rustdoc` will show item deprecation, including the `since` version and `note`, if available. +r[attributes.diagnostics.deprectead.syntax] The `deprecated` attribute has several forms: - `deprecated` --- Issues a generic message. @@ -293,6 +326,7 @@ The `deprecated` attribute has several forms: message. This is typically used to provide an explanation about the deprecation and preferred alternatives. +r[attributes.diagnostics.deprecated.application] The `deprecated` attribute may be applied to any [item], [trait item], [enum variant], [struct field], [external block item], or [macro definition]. It cannot be applied to [trait implementation items]. When applied to an item @@ -318,15 +352,20 @@ The [RFC][1270-deprecation.md] contains motivations and more details. ## The `must_use` attribute +r[attributes.diagnostics.must_use] + +r[attributes.diagnostics.must_use.application] The *`must_use` attribute* is used to issue a diagnostic warning when a value is not "used". It can be applied to user-defined composite types ([`struct`s][struct], [`enum`s][enum], and [`union`s][union]), [functions], and [traits]. +r[attributes.diagnostics.must_use.syntax] The `must_use` attribute may include a message by using the [_MetaNameValueStr_] syntax such as `#[must_use = "example message"]`. The message will be given alongside the warning. +r[attributes.diagnostics.must_use.types] When used on user-defined composite types, if the [expression] of an [expression statement] has that type, then the `unused_must_use` lint is violated. @@ -345,6 +384,7 @@ struct MustUse { MustUse::new(); ``` +r[attributes.diagnostics.must_use.function] When used on a function, if the [expression] of an [expression statement] is a [call expression] to that function, then the `unused_must_use` lint is violated. @@ -357,6 +397,7 @@ fn five() -> i32 { 5i32 } five(); ``` +r[attributes.diagnostics.must_use.traits] When used on a [trait declaration], a [call expression] of an [expression statement] to a function that returns an [impl trait] or a [dyn trait] of that trait violates the `unused_must_use` lint. @@ -374,6 +415,7 @@ fn get_critical() -> impl Critical { get_critical(); ``` +r[attributes.diagnostics.must_use.trait-function] When used on a function in a trait declaration, then the behavior also applies when the call expression is a function from an implementation of the trait. @@ -391,6 +433,7 @@ impl Trait for i32 { 5i32.use_me(); ``` +r[attributes.diagnostics.must_use.impl-function] When used on a function in a trait implementation, the attribute does nothing. > Note: Trivial no-op expressions containing the value will not violate the @@ -425,36 +468,59 @@ When used on a function in a trait implementation, the attribute does nothing. ## The `diagnostic` tool attribute namespace +r[attributes.diagnostics.namespace] + +r[attributes.diagnostics.namespace.general] The `#[diagnostic]` attribute namespace is a home for attributes to influence compile-time error messages. The hints provided by these attributes are not guaranteed to be used. + +r[attributes.diagnostics.namespace.unknown-invalid-syntax] Unknown attributes in this namespace are accepted, though they may emit warnings for unused attributes. Additionally, invalid inputs to known attributes will typically be a warning (see the attribute definitions for details). This is meant to allow adding or discarding attributes and changing inputs in the future to allow changes without the need to keep the non-meaningful attributes or options working. ### The `diagnostic::on_unimplemented` attribute +r[attributes.diagnostics.on_unimplemented] + +r[attributes.diagnostics.on_unimplemented.general] The `#[diagnostic::on_unimplemented]` attribute is a hint to the compiler to supplement the error message that would normally be generated in scenarios where a trait is required but not implemented on a type. + +r[attributes.diagnostics.on_unimplemented.restriction] The attribute should be placed on a [trait declaration], though it is not an error to be located in other positions. + +r[attributes.diagnostics.on_unimplemented.syntax] The attribute uses the [_MetaListNameValueStr_] syntax to specify its inputs, though any malformed input to the attribute is not considered as an error to provide both forwards and backwards compatibility. -The following keys have the given meaning: + +r[attributes.diagnostics.on_unimplemented.keys] +The following keys have the given meaning: * `message` --- The text for the top level error message. * `label` --- The text for the label shown inline in the broken code in the error message. * `note` --- Provides additional notes. +r[attributes.diagnostics.on_unimplemented-note-repetition] The `note` option can appear several times, which results in several note messages being emitted. + +r[attributes.diagnostics.on_unimplemented.repetition] If any of the other options appears several times the first occurrence of the relevant option specifies the actually used value. + +r[attributes.diagnostics.on_unimplemented.warnings] Any other occurrence generates an lint warning. For any other non-existing option a lint-warning is generated. +r[attributes.diagnostics.format-string] All three options accept a string as an argument, interpreted using the same formatting as a [`std::fmt`] string. -Format parameters with the given named parameter will be replaced with the following text: +r[attributes.diagnostics.format-parameters] +Format parameters with the given named parameter will be replaced with the following text: * `{Self}` --- The name of the type implementing the trait. * `{` *GenericParameterName* `}` --- The name of the generic argument's type for the given generic parameter. +r[attributes.diagnostics.invalid-formats] Any other format parameter will generate a warning, but will otherwise be included in the string as-is. +r[attributes.diagnostics.invalid-string] Invalid format strings may generate a warning, but are otherwise allowed, but may not display as intended. Format specifiers may generate a warning, but are otherwise ignored. From 20f1ff14ee9ab56c25e06b2fe55cf2b51fb91401 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 13:04:48 -0400 Subject: [PATCH 135/189] Add identifier syntax to attributes.limits --- src/attributes/limits.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/attributes/limits.md b/src/attributes/limits.md index 79f292a..a8af235 100644 --- a/src/attributes/limits.md +++ b/src/attributes/limits.md @@ -1,12 +1,20 @@ # Limits +r[attributes.limits] + The following [attributes] affect compile-time limits. ## The `recursion_limit` attribute +r[attributes.limits.recursion_limits] + +r[attributes.limits.recursion_limits.application] The *`recursion_limit` attribute* may be applied at the [crate] level to set the maximum depth for potentially infinitely-recursive compile-time operations -like macro expansion or auto-dereference. It uses the [_MetaNameValueStr_] +like macro expansion or auto-dereference. + +r[attributes.limits.recursion_limits.syntax] +It uses the [_MetaNameValueStr_] syntax to specify the recursion depth. > Note: The default in `rustc` is 128. @@ -35,12 +43,17 @@ a!{} ## The `type_length_limit` attribute +r[attributes.limits.type_length_limit] + > **Note**: This limit is only enforced when the nightly `-Zenforce-type-length-limit` flag is active. > > For more information, see . +r[attributes.limits.type_length_limit.general] The *`type_length_limit` attribute* limits the maximum number of type substitutions made when constructing a concrete type during monomorphization. + +r[attributes.limits.type_length_limit.restriction] It is applied at the [crate] level, and uses the [_MetaNameValueStr_] syntax to set the limit based on the number of type substitutions. From 23652c538ae04fc0c079dfc7f6d6377925899198 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 13:09:10 -0400 Subject: [PATCH 136/189] Add identifier syntax to attributes.testing --- src/attributes/testing.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/attributes/testing.md b/src/attributes/testing.md index a2db083..4a303d3 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -1,5 +1,7 @@ # Testing attributes +r[attributes.testing] + The following [attributes] are used for specifying functions for performing tests. Compiling a crate in "test" mode enables building the test functions along with a test harness for executing the tests. Enabling the test mode also @@ -7,9 +9,17 @@ enables the [`test` conditional compilation option]. ## The `test` attribute -The *`test` attribute* marks a function to be executed as a test. These -functions are only compiled when in test mode. Test functions must be free, -monomorphic functions that take no arguments, and the return type must implement the [`Termination`] trait, for example: +r[attributes.testing.test] + + +r[attributes.testing.test.general] +The *`test` attribute* marks a function to be executed as a test. + +r[attributes.testing.test.enabled] +These functions are only compiled when in test mode. + +r[attributes.testing.test.restriction] +Test functions must be free, monomorphic functions that take no arguments, and the return type must implement the [`Termination`] trait, for example: * `()` * `Result where T: Termination, E: Debug` @@ -21,6 +31,7 @@ monomorphic functions that take no arguments, and the return type must implement > Note: The test mode is enabled by passing the `--test` argument to `rustc` > or using `cargo test`. +r[attributes.testing.success] The test harness calls the returned value's [`report`] method, and classifies the test as passed or failed depending on whether the resulting [`ExitCode`] represents successful termination. In particular: * Tests that return `()` pass as long as they terminate and do not panic. @@ -42,10 +53,15 @@ fn test_the_thing() -> io::Result<()> { ## The `ignore` attribute +r[attributes.testing.ignore] + + +r[attributes.testing.ignore.general] A function annotated with the `test` attribute can also be annotated with the `ignore` attribute. The *`ignore` attribute* tells the test harness to not execute that function as a test. It will still be compiled when in test mode. +r[attributes.testing.ignore.syntax] The `ignore` attribute may optionally be written with the [_MetaNameValueStr_] syntax to specify a reason why the test is ignored. @@ -62,10 +78,17 @@ fn mytest() { ## The `should_panic` attribute +r[attributes.testing.should_panic] + +r[attributes.testing.should_panic.restriction] A function annotated with the `test` attribute that returns `()` can also be -annotated with the `should_panic` attribute. The *`should_panic` attribute* +annotated with the `should_panic` attribute. + +r[attributes.testing.should_panic.behaviour] +The *`should_panic` attribute* makes the test only pass if it actually panics. +r[attributes.testing.should_panic.syntax] The `should_panic` attribute may optionally take an input string that must appear within the panic message. If the string is not found in the message, then the test will fail. The string may be passed using the From 3d14faf239299e1049152d025a95a21805956595 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 6 Aug 2024 13:12:52 -0400 Subject: [PATCH 137/189] Add identifier syntax to attributes.type_system --- src/attributes/type_system.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index d3ea632..b2a677e 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -1,16 +1,26 @@ # Type system attributes +r[attributes.type-system] + The following [attributes] are used for changing how a type can be used. ## The `non_exhaustive` attribute +r[attributes.type-system.non_exhaustive] + + +r[attributes.type-system.non_exhaustive.general] The *`non_exhaustive` attribute* indicates that a type or variant may have -more fields or variants added in the future. It can be applied to -[`struct`s][struct], [`enum`s][enum], and `enum` variants. +more fields or variants added in the future. + +r[attributes.type-system.non_exhaustive.restriction] +It can be applied to [`struct`s][struct], [`enum`s][enum], and `enum` variants. +r[attributes.type-system.non_exhaustive.syntax] The `non_exhaustive` attribute uses the [_MetaWord_] syntax and thus does not take any inputs. +r[attributes.type-system.non_exhaustive.same-crate] Within the defining crate, `non_exhaustive` has no effect. ```rust @@ -65,9 +75,11 @@ match message { } ``` +r[attributes.type-system.non_exhaustive.external-crate] Outside of the defining crate, types annotated with `non_exhaustive` have limitations that preserve backwards compatibility when new fields or variants are added. +r[attributes.type-system.non_exhaustive.construction] Non-exhaustive types cannot be constructed outside of the defining crate: - Non-exhaustive variants ([`struct`][struct] or [`enum` variant][enum]) cannot be constructed @@ -119,6 +131,7 @@ let message = Message::Reaction(0); let message = Message::Quit; ``` +r[attributes.type-system.non_exhaustive.match] There are limitations when matching on non-exhaustive types outside of the defining crate: - When pattern matching on a non-exhaustive variant ([`struct`][struct] or [`enum` variant][enum]), From 6f39e373be684bcc33359f713b36ee7472a9d512 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:06:25 -0400 Subject: [PATCH 138/189] Fix style in modified chapters --- src/attributes/codegen.md | 2 +- src/attributes/derive.md | 2 +- src/attributes/diagnostics.md | 2 +- src/attributes/limits.md | 2 +- src/attributes/testing.md | 6 +++--- src/attributes/type_system.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 0e170ce..33fa0be 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -347,7 +347,7 @@ r[attributes.codegen.track_caller] r[attributes.codegen.track_caller.restriction] The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] -with the exception of the entry point `fn main`. +with the exception of the entry point `fn main`. r[attributes.codegen.track_caller.traits] When applied to functions and methods in trait declarations, the attribute applies to all implementations. If the trait provides a diff --git a/src/attributes/derive.md b/src/attributes/derive.md index c8938f3..03f9fc4 100644 --- a/src/attributes/derive.md +++ b/src/attributes/derive.md @@ -5,7 +5,7 @@ r[attributes.derive] r[attributes.derived.general] The *`derive` attribute* allows new [items] to be automatically generated for -data structures. +data structures. r[attributes.derive.syntax] It uses the [_MetaListPaths_] syntax to specify a list of diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index d1dde2e..1cf259a 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -10,7 +10,7 @@ messages during compilation. r[attributes.diagnostics.lints] A lint check names a potentially undesirable coding pattern, such as -unreachable code or omitted documentation. +unreachable code or omitted documentation. r[attributes.diagnostics.lints.level] The lint attributes `allow`, diff --git a/src/attributes/limits.md b/src/attributes/limits.md index a8af235..b02e9c5 100644 --- a/src/attributes/limits.md +++ b/src/attributes/limits.md @@ -11,7 +11,7 @@ r[attributes.limits.recursion_limits] r[attributes.limits.recursion_limits.application] The *`recursion_limit` attribute* may be applied at the [crate] level to set the maximum depth for potentially infinitely-recursive compile-time operations -like macro expansion or auto-dereference. +like macro expansion or auto-dereference. r[attributes.limits.recursion_limits.syntax] It uses the [_MetaNameValueStr_] diff --git a/src/attributes/testing.md b/src/attributes/testing.md index 4a303d3..4d9706f 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -13,10 +13,10 @@ r[attributes.testing.test] r[attributes.testing.test.general] -The *`test` attribute* marks a function to be executed as a test. +The *`test` attribute* marks a function to be executed as a test. r[attributes.testing.test.enabled] -These functions are only compiled when in test mode. +These functions are only compiled when in test mode. r[attributes.testing.test.restriction] Test functions must be free, monomorphic functions that take no arguments, and the return type must implement the [`Termination`] trait, for example: @@ -82,7 +82,7 @@ r[attributes.testing.should_panic] r[attributes.testing.should_panic.restriction] A function annotated with the `test` attribute that returns `()` can also be -annotated with the `should_panic` attribute. +annotated with the `should_panic` attribute. r[attributes.testing.should_panic.behaviour] The *`should_panic` attribute* diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index b2a677e..cccdba1 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -11,7 +11,7 @@ r[attributes.type-system.non_exhaustive] r[attributes.type-system.non_exhaustive.general] The *`non_exhaustive` attribute* indicates that a type or variant may have -more fields or variants added in the future. +more fields or variants added in the future. r[attributes.type-system.non_exhaustive.restriction] It can be applied to [`struct`s][struct], [`enum`s][enum], and `enum` variants. From 3397e09023954a5c75e5f6a3a1a844fd192c6e90 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:09:10 -0400 Subject: [PATCH 139/189] Appease link-checker --- src/attributes.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index 794f875..fb37ad5 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -1,9 +1,6 @@ {{#include attributes-redirect.html}} # Attributes -r[attributes] - - r[attributes.syntax] > **Syntax**\ > _InnerAttribute_ :\ From e31ed9787db4c68c5a37586325540e624216c825 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 10 Sep 2024 17:48:13 +0000 Subject: [PATCH 140/189] Apply suggestions from PR review --- src/attributes.md | 8 +-- src/attributes/codegen.md | 14 +++--- src/attributes/debugger.md | 14 +++--- src/attributes/derive.md | 2 +- src/attributes/diagnostics.md | 92 +++++++++++++++++------------------ src/attributes/limits.md | 8 +-- src/attributes/testing.md | 4 +- src/attributes/type_system.md | 2 +- 8 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index fb37ad5..02588b2 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -17,7 +17,7 @@ r[attributes.syntax] >       [_DelimTokenTree_]\ >    | `=` [_Expression_] -r[attributes.general] +r[attributes.intro] An _attribute_ is a general, free-form metadatum that is interpreted according to name, convention, language, and compiler version. Attributes are modeled on Attributes in [ECMA-335], with the syntax coming from [ECMA-334] \(C#). @@ -108,7 +108,7 @@ fn some_unused_variables() { r[attributes.meta] -r[attributes.meta.general] +r[attributes.meta.intro] A "meta item" is the syntax used for the _Attr_ rule by most [built-in attributes]. It has the following grammar: @@ -191,7 +191,7 @@ _MetaListNameValueStr_ | `link(name = "CoreFoundation", kind = "framework")` r[attributes.activity] -r[attributes.activity.general] +r[attributes.activity.intro] An attribute is either active or inert. During attribute processing, *active attributes* remove themselves from the thing they are on while *inert attributes* stay on. @@ -204,7 +204,7 @@ active. All other attributes are inert. r[attributes.tool] -r[attributes.tool.general] +r[attributes.tool.intro] The compiler may allow attributes for external tools where each tool resides in its own module in the [tool prelude]. The first segment of the attribute path is the name of the tool, with one or more additional segments whose diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 33fa0be..cb27e21 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -23,7 +23,7 @@ have no effect on a trait function without a body. r[attributes.codgen.inline] -r[attributes.codegen.inline.general] +r[attributes.codegen.inline.intro] The *`inline` [attribute]* suggests that a copy of the attributed function should be placed in the caller, rather than generating code to call the function where it is defined. @@ -64,7 +64,7 @@ assumed to exist. r[attributes.codegen.target_feature] -r[attributes.codegen.target_feature.general] +r[attributes.codegen.target_feature.intro] The *`target_feature` [attribute]* may be applied to a function to enable code generation of that function for specific platform architecture features. It uses the [_MetaListNameValueStr_] syntax with a single key of @@ -76,17 +76,17 @@ features. It uses the [_MetaListNameValueStr_] syntax with a single key of unsafe fn foo_avx2() {} ``` -r[attributes.codegen.target_features.arch] +r[attributes.codegen.target_feature.arch] Each [target architecture] has a set of features that may be enabled. It is an error to specify a feature for a target architecture that the crate is not being compiled for. -r[attributes.codegen.target_features.precondition] +r[attributes.codegen.target_feature.precondition] It is [undefined behavior] to call a function that is compiled with a feature that is not supported on the current platform the code is running on, *except* if the platform explicitly documents this to be safe. -r[attributes.codegen.target_features.restriction] +r[attributes.codegen.target_feature.restriction-inline] Functions marked with `target_feature` are not inlined into a context that does not support the given features. The `#[inline(always)]` attribute may not be used with a `target_feature` attribute. @@ -361,7 +361,7 @@ otherwise undefined behavior results. ### Behavior -r[attributes.codegen.track_caller.behaviour] +r[attributes.codegen.track_caller.behavior] Applying the attribute to a function `f` allows code within `f` to get a hint of the [`Location`] of the "topmost" tracked call that led to `f`'s invocation. At the point of observation, an implementation behaves as if it walks up the stack from `f`'s frame to find the nearest frame of an @@ -443,7 +443,7 @@ And so on. r[attributes.codegen.track_caller.limits] -r[attributes.codegent.track_caller.hint] +r[attributes.codegen.track_caller.hint] This information is a hint and implementations are not required to preserve it. r[attributes.codegen.track_caller.decay] diff --git a/src/attributes/debugger.md b/src/attributes/debugger.md index 44e05e8..40074b5 100644 --- a/src/attributes/debugger.md +++ b/src/attributes/debugger.md @@ -8,7 +8,7 @@ The following [attributes] are used for enhancing the debugging experience when r[attributes.debugger.debugger_visualizer] -r[attributes.debugger.debugger_visualizer.general] +r[attributes.debugger.debugger_visualizer.intro] The *`debugger_visualizer` attribute* can be used to embed a debugger visualizer file into the debug information. This enables an improved debugger experience for displaying values in the debugger. @@ -19,14 +19,14 @@ It uses the [_MetaListNameValueStr_] syntax to specify its inputs, and must be s r[attributes.debugger.debugger_visualizer.natvis] -r[attributes.debugger.debugger_visualizer.natvis-general] +r[attributes.debugger.debugger_visualizer.natvis.intro] Natvis is an XML-based framework for Microsoft debuggers (such as Visual Studio and WinDbg) that uses declarative rules to customize the display of types. For detailed information on the Natvis format, refer to Microsoft's [Natvis documentation]. -r[attributes.debugger.debugger_visualizer.natvis-restrictions] +r[attributes.debugger.debugger_visualizer.natvis.restrictions] This attribute only supports embedding Natvis files on `-windows-msvc` targets. -r[attributes.debugger.debugger_visualizer.natvis-path] +r[attributes.debugger.debugger_visualizer.natvis.path] The path to the Natvis file is specified with the `natvis_file` key, which is a path relative to the crate source file: @@ -87,7 +87,7 @@ When viewed under WinDbg, the `fancy_rect` variable would be shown as follows: r[attributes.debugger.debugger_visualizer.gdb] -r[attributes.debugger.debugger_visualizer.gdb-pretty] +r[attributes.debugger.debugger_visualizer.gdb.pretty] GDB supports the use of a structured Python script, called a *pretty printer*, that describes how a type should be visualized in the debugger view. For detailed information on pretty printers, refer to GDB's [pretty printing documentation]. @@ -97,7 +97,7 @@ There are two ways to enable auto-loading embedded pretty printers: For more information, see GDB's [auto-loading documentation]. 1. Create a file named `gdbinit` under `$HOME/.config/gdb` (you may need to create the directory if it doesn't already exist). Add the following line to that file: `add-auto-load-safe-path path/to/binary`. -r[attributes.debugger.debugger_visualizer.gdb-path] +r[attributes.debugger.debugger_visualizer.gdb.path] These scripts are embedded using the `gdb_script_file` key, which is a path relative to the crate source file. @@ -162,7 +162,7 @@ When the crate's debug executable is passed into GDB[^rust-gdb], `print bob` wil r[attributes.debugger.collapse_debuginfo] -r[attributes.debugger.collapse_debuginfo.general] +r[attributes.debugger.collapse_debuginfo.intro] The *`collapse_debuginfo` [attribute]* controls whether code locations from a macro definition are collapsed into a single location associated with the macro's call site, when generating debuginfo for code calling this macro. diff --git a/src/attributes/derive.md b/src/attributes/derive.md index 03f9fc4..07238c4 100644 --- a/src/attributes/derive.md +++ b/src/attributes/derive.md @@ -3,7 +3,7 @@ r[attributes.derive] -r[attributes.derived.general] +r[attributes.derive.intro] The *`derive` attribute* allows new [items] to be automatically generated for data structures. diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 1cf259a..dbbf6ce 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -1,18 +1,18 @@ # Diagnostic attributes -r[attributes.diagnostics] +r[attributes.diagnostic] The following [attributes] are used for controlling or generating diagnostic messages during compilation. ## Lint check attributes -r[attributes.diagnostics.lints] +r[attributes.diagnostic.lint] A lint check names a potentially undesirable coding pattern, such as unreachable code or omitted documentation. -r[attributes.diagnostics.lints.level] +r[attributes.diagnostic.lint.level] The lint attributes `allow`, `expect`, `warn`, `deny`, and `forbid` use the [_MetaListPaths_] syntax to specify a list of lint names to change the lint level for the entity @@ -20,22 +20,22 @@ to which the attribute applies. For any lint check `C`: -r[attributes.diagnostics.lints.allow] +r[attributes.diagnostic.lint.allow] * `#[allow(C)]` overrides the check for `C` so that violations will go unreported. -r[attributes.diagnostics.lints.expect] +r[attributes.diagnostic.lint.expect] * `#[expect(C)]` indicates that lint `C` is expected to be emitted. The attribute will suppress the emission of `C` or issue a warning, if the expectation is unfulfilled. -r[attributes.diagnostics.lints.warn] +r[attributes.diagnostic.lint.warn] * `#[warn(C)]` warns about violations of `C` but continues compilation. -r[attributes.diagnostics.lints.deny] +r[attributes.diagnostic.lint.deny] * `#[deny(C)]` signals an error after encountering a violation of `C`, -r[attributes.diagnostics.lints.forbid] +r[attributes.diagnostic.lint.forbid] * `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint level afterwards, @@ -58,7 +58,7 @@ pub mod m1 { } ``` -r[attributes.diagnostics.lints.override] +r[attributes.diagnostic.lint.override] Lint attributes can override the level specified from a previous attribute, as long as the level does not attempt to change a forbidden lint (except for `deny`, which is allowed inside a `forbid` context, but ignored). @@ -106,7 +106,7 @@ pub mod m3 { ### Lint Reasons -r[attributes.diagnostics.lints.reason] +r[attributes.diagnostic.lint.reason] All lint attributes support an additional `reason` parameter, to give context why a certain attribute was added. This reason will be displayed as part of the lint message if the lint is emitted at the defined level. @@ -143,9 +143,9 @@ pub fn get_path() -> PathBuf { ### The `#[expect]` attribute -r[attributes.diagnostics.expect] +r[attributes.diagnostic.expect] -r[attributes.diagnostics.expect.general] +r[attributes.diagnostic.expect.intro] The `#[expect(C)]` attribute creates a lint expectation for lint `C`. The expectation will be fulfilled, if a `#[warn(C)]` attribute at the same location would result in a lint emission. If the expectation is unfulfilled, because @@ -171,7 +171,7 @@ fn main() { } ``` -r[attributes.lints.expect.fulfilment] +r[attributes.lints.expect.fulfillment] The lint expectation is only fulfilled by lint emissions which have been suppressed by the `expect` attribute. If the lint level is modified in the scope with other level attributes like `allow` or `warn`, the lint emission will be handled accordingly and the @@ -201,7 +201,7 @@ fn select_song() { } ``` -r[attributes.diagnostics.expect.independent] +r[attributes.diagnostic.expect.independent] If the `expect` attribute contains several lints, each one is expected separately. For a lint group it's enough if one lint inside the group has been emitted: @@ -230,7 +230,7 @@ pub fn another_example() { ### Lint groups -r[attributes.lints.groups] +r[attributes.diagnostic.lint.group] Lints may be organized into named groups so that the level of related lints can be adjusted together. Using a named group is equivalent to listing out the lints within that group. @@ -251,7 +251,7 @@ fn example() { } ``` -r[attributes.lints.warnings-group] +r[attributes.diagnostic.lint.group.warnings] There is a special group named "warnings" which includes all lints at the "warn" level. The "warnings" group ignores attribute order and applies to all lints that would otherwise warn within the entity. @@ -271,13 +271,13 @@ fn example_err() { ### Tool lint attributes -r[attributes.lints.tools] +r[attributes.diagnostic.lint.tool] -r[attributes.lints.tools.general] +r[attributes.diagnostic.lint.tool.intro] Tool lints allows using scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of certain tools. -r[attributes.lints.tools.activation] +r[attributes.diagnostic.lint.tool.activation] Tool lints only get checked when the associated tool is active. If a lint attribute, such as `allow`, references a nonexistent tool lint, the compiler will not warn about the nonexistent lint until you use the tool. @@ -305,14 +305,14 @@ fn foo() { ## The `deprecated` attribute -r[attributes.diagnostics.deprecated] +r[attributes.diagnostic.deprecated] -r[attributes.diagnostics.deprecated.general] +r[attributes.diagnostic.deprecated.intro] The *`deprecated` attribute* marks an item as deprecated. `rustc` will issue warnings on usage of `#[deprecated]` items. `rustdoc` will show item deprecation, including the `since` version and `note`, if available. -r[attributes.diagnostics.deprectead.syntax] +r[attributes.diagnostic.deprecated.syntax] The `deprecated` attribute has several forms: - `deprecated` --- Issues a generic message. @@ -326,7 +326,7 @@ The `deprecated` attribute has several forms: message. This is typically used to provide an explanation about the deprecation and preferred alternatives. -r[attributes.diagnostics.deprecated.application] +r[attributes.diagnostic.deprecated.application] The `deprecated` attribute may be applied to any [item], [trait item], [enum variant], [struct field], [external block item], or [macro definition]. It cannot be applied to [trait implementation items]. When applied to an item @@ -352,20 +352,20 @@ The [RFC][1270-deprecation.md] contains motivations and more details. ## The `must_use` attribute -r[attributes.diagnostics.must_use] +r[attributes.diagnostic.must_use] -r[attributes.diagnostics.must_use.application] +r[attributes.diagnostic.must_use.application] The *`must_use` attribute* is used to issue a diagnostic warning when a value is not "used". It can be applied to user-defined composite types ([`struct`s][struct], [`enum`s][enum], and [`union`s][union]), [functions], and [traits]. -r[attributes.diagnostics.must_use.syntax] +r[attributes.diagnostic.must_use.syntax] The `must_use` attribute may include a message by using the [_MetaNameValueStr_] syntax such as `#[must_use = "example message"]`. The message will be given alongside the warning. -r[attributes.diagnostics.must_use.types] +r[attributes.diagnostic.must_use.type] When used on user-defined composite types, if the [expression] of an [expression statement] has that type, then the `unused_must_use` lint is violated. @@ -384,7 +384,7 @@ struct MustUse { MustUse::new(); ``` -r[attributes.diagnostics.must_use.function] +r[attributes.diagnostic.must_use.fn] When used on a function, if the [expression] of an [expression statement] is a [call expression] to that function, then the `unused_must_use` lint is violated. @@ -397,7 +397,7 @@ fn five() -> i32 { 5i32 } five(); ``` -r[attributes.diagnostics.must_use.traits] +r[attributes.diagnostic.must_use.trait] When used on a [trait declaration], a [call expression] of an [expression statement] to a function that returns an [impl trait] or a [dyn trait] of that trait violates the `unused_must_use` lint. @@ -415,7 +415,7 @@ fn get_critical() -> impl Critical { get_critical(); ``` -r[attributes.diagnostics.must_use.trait-function] +r[attributes.diagnostic.must_use.trait-function] When used on a function in a trait declaration, then the behavior also applies when the call expression is a function from an implementation of the trait. @@ -433,7 +433,7 @@ impl Trait for i32 { 5i32.use_me(); ``` -r[attributes.diagnostics.must_use.impl-function] +r[attributes.diagnostic.must_use.trait-impl-function] When used on a function in a trait implementation, the attribute does nothing. > Note: Trivial no-op expressions containing the value will not violate the @@ -468,59 +468,59 @@ When used on a function in a trait implementation, the attribute does nothing. ## The `diagnostic` tool attribute namespace -r[attributes.diagnostics.namespace] +r[attributes.diagnostic.namespace] -r[attributes.diagnostics.namespace.general] +r[attributes.diagnostic.namespace.intro] The `#[diagnostic]` attribute namespace is a home for attributes to influence compile-time error messages. The hints provided by these attributes are not guaranteed to be used. -r[attributes.diagnostics.namespace.unknown-invalid-syntax] +r[attributes.diagnostic.namespace.unknown-invalid-syntax] Unknown attributes in this namespace are accepted, though they may emit warnings for unused attributes. Additionally, invalid inputs to known attributes will typically be a warning (see the attribute definitions for details). This is meant to allow adding or discarding attributes and changing inputs in the future to allow changes without the need to keep the non-meaningful attributes or options working. ### The `diagnostic::on_unimplemented` attribute -r[attributes.diagnostics.on_unimplemented] +r[attributes.diagnostic.on_unimplemented] -r[attributes.diagnostics.on_unimplemented.general] +r[attributes.diagnostic.on_unimplemented.intro] The `#[diagnostic::on_unimplemented]` attribute is a hint to the compiler to supplement the error message that would normally be generated in scenarios where a trait is required but not implemented on a type. -r[attributes.diagnostics.on_unimplemented.restriction] +r[attributes.diagnostic.on_unimplemented.restriction] The attribute should be placed on a [trait declaration], though it is not an error to be located in other positions. -r[attributes.diagnostics.on_unimplemented.syntax] +r[attributes.diagnostic.on_unimplemented.syntax] The attribute uses the [_MetaListNameValueStr_] syntax to specify its inputs, though any malformed input to the attribute is not considered as an error to provide both forwards and backwards compatibility. -r[attributes.diagnostics.on_unimplemented.keys] +r[attributes.diagnostic.on_unimplemented.keys] The following keys have the given meaning: * `message` --- The text for the top level error message. * `label` --- The text for the label shown inline in the broken code in the error message. * `note` --- Provides additional notes. -r[attributes.diagnostics.on_unimplemented-note-repetition] +r[attributes.diagnostic.on_unimplemented-note-repetition] The `note` option can appear several times, which results in several note messages being emitted. -r[attributes.diagnostics.on_unimplemented.repetition] +r[attributes.diagnostic.on_unimplemented.repetition] If any of the other options appears several times the first occurrence of the relevant option specifies the actually used value. -r[attributes.diagnostics.on_unimplemented.warnings] +r[attributes.diagnostic.on_unimplemented.warnings] Any other occurrence generates an lint warning. For any other non-existing option a lint-warning is generated. -r[attributes.diagnostics.format-string] +r[attributes.diagnostic.format-string] All three options accept a string as an argument, interpreted using the same formatting as a [`std::fmt`] string. -r[attributes.diagnostics.format-parameters] +r[attributes.diagnostic.format-parameters] Format parameters with the given named parameter will be replaced with the following text: * `{Self}` --- The name of the type implementing the trait. * `{` *GenericParameterName* `}` --- The name of the generic argument's type for the given generic parameter. -r[attributes.diagnostics.invalid-formats] +r[attributes.diagnostic.invalid-formats] Any other format parameter will generate a warning, but will otherwise be included in the string as-is. -r[attributes.diagnostics.invalid-string] +r[attributes.diagnostic.invalid-string] Invalid format strings may generate a warning, but are otherwise allowed, but may not display as intended. Format specifiers may generate a warning, but are otherwise ignored. diff --git a/src/attributes/limits.md b/src/attributes/limits.md index b02e9c5..edfff4a 100644 --- a/src/attributes/limits.md +++ b/src/attributes/limits.md @@ -6,14 +6,14 @@ The following [attributes] affect compile-time limits. ## The `recursion_limit` attribute -r[attributes.limits.recursion_limits] +r[attributes.limits.recursion_limit] -r[attributes.limits.recursion_limits.application] +r[attributes.limits.recursion_limit.application] The *`recursion_limit` attribute* may be applied at the [crate] level to set the maximum depth for potentially infinitely-recursive compile-time operations like macro expansion or auto-dereference. -r[attributes.limits.recursion_limits.syntax] +r[attributes.limits.recursion_limit.syntax] It uses the [_MetaNameValueStr_] syntax to specify the recursion depth. @@ -49,7 +49,7 @@ r[attributes.limits.type_length_limit] > > For more information, see . -r[attributes.limits.type_length_limit.general] +r[attributes.limits.type_length_limit.intro] The *`type_length_limit` attribute* limits the maximum number of type substitutions made when constructing a concrete type during monomorphization. diff --git a/src/attributes/testing.md b/src/attributes/testing.md index 4d9706f..c360292 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -12,7 +12,7 @@ enables the [`test` conditional compilation option]. r[attributes.testing.test] -r[attributes.testing.test.general] +r[attributes.testing.test.intro] The *`test` attribute* marks a function to be executed as a test. r[attributes.testing.test.enabled] @@ -56,7 +56,7 @@ fn test_the_thing() -> io::Result<()> { r[attributes.testing.ignore] -r[attributes.testing.ignore.general] +r[attributes.testing.ignore.intro] A function annotated with the `test` attribute can also be annotated with the `ignore` attribute. The *`ignore` attribute* tells the test harness to not execute that function as a test. It will still be compiled when in test mode. diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index cccdba1..ebbb8af 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -9,7 +9,7 @@ The following [attributes] are used for changing how a type can be used. r[attributes.type-system.non_exhaustive] -r[attributes.type-system.non_exhaustive.general] +r[attributes.type-system.non_exhaustive.intro] The *`non_exhaustive` attribute* indicates that a type or variant may have more fields or variants added in the future. From b5362cc59ed1f912b8c77dd06513a20963b1f629 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 14:32:01 -0400 Subject: [PATCH 141/189] Replace uses of `constraint` and `restriction` in attributes chapters. --- src/attributes/codegen.md | 2 +- src/attributes/debugger.md | 4 ++-- src/attributes/diagnostics.md | 2 +- src/attributes/limits.md | 2 +- src/attributes/testing.md | 4 ++-- src/attributes/type_system.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index cb27e21..314b38f 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -86,7 +86,7 @@ It is [undefined behavior] to call a function that is compiled with a feature that is not supported on the current platform the code is running on, *except* if the platform explicitly documents this to be safe. -r[attributes.codegen.target_feature.restriction-inline] +r[attributes.codegen.target_feature.inline] Functions marked with `target_feature` are not inlined into a context that does not support the given features. The `#[inline(always)]` attribute may not be used with a `target_feature` attribute. diff --git a/src/attributes/debugger.md b/src/attributes/debugger.md index 40074b5..fb27af8 100644 --- a/src/attributes/debugger.md +++ b/src/attributes/debugger.md @@ -12,7 +12,7 @@ r[attributes.debugger.debugger_visualizer.intro] The *`debugger_visualizer` attribute* can be used to embed a debugger visualizer file into the debug information. This enables an improved debugger experience for displaying values in the debugger. -r[attributes.debugger.debugger_visualizer.restriction] +r[attributes.debugger.debugger_visualizer.syntax] It uses the [_MetaListNameValueStr_] syntax to specify its inputs, and must be specified as a crate attribute. ### Using `debugger_visualizer` with Natvis @@ -23,7 +23,7 @@ r[attributes.debugger.debugger_visualizer.natvis.intro] Natvis is an XML-based framework for Microsoft debuggers (such as Visual Studio and WinDbg) that uses declarative rules to customize the display of types. For detailed information on the Natvis format, refer to Microsoft's [Natvis documentation]. -r[attributes.debugger.debugger_visualizer.natvis.restrictions] +r[attributes.debugger.debugger_visualizer.natvis.msvc] This attribute only supports embedding Natvis files on `-windows-msvc` targets. r[attributes.debugger.debugger_visualizer.natvis.path] diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index dbbf6ce..5e910c4 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -486,7 +486,7 @@ r[attributes.diagnostic.on_unimplemented] r[attributes.diagnostic.on_unimplemented.intro] The `#[diagnostic::on_unimplemented]` attribute is a hint to the compiler to supplement the error message that would normally be generated in scenarios where a trait is required but not implemented on a type. -r[attributes.diagnostic.on_unimplemented.restriction] +r[attributes.diagnostic.on_unimplemented.application] The attribute should be placed on a [trait declaration], though it is not an error to be located in other positions. r[attributes.diagnostic.on_unimplemented.syntax] diff --git a/src/attributes/limits.md b/src/attributes/limits.md index edfff4a..7e06cb4 100644 --- a/src/attributes/limits.md +++ b/src/attributes/limits.md @@ -53,7 +53,7 @@ r[attributes.limits.type_length_limit.intro] The *`type_length_limit` attribute* limits the maximum number of type substitutions made when constructing a concrete type during monomorphization. -r[attributes.limits.type_length_limit.restriction] +r[attributes.limits.type_length_limit.syntax] It is applied at the [crate] level, and uses the [_MetaNameValueStr_] syntax to set the limit based on the number of type substitutions. diff --git a/src/attributes/testing.md b/src/attributes/testing.md index c360292..5174d10 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -18,7 +18,7 @@ The *`test` attribute* marks a function to be executed as a test. r[attributes.testing.test.enabled] These functions are only compiled when in test mode. -r[attributes.testing.test.restriction] +r[attributes.testing.test.target] Test functions must be free, monomorphic functions that take no arguments, and the return type must implement the [`Termination`] trait, for example: * `()` @@ -80,7 +80,7 @@ fn mytest() { r[attributes.testing.should_panic] -r[attributes.testing.should_panic.restriction] +r[attributes.testing.should_panic.target] A function annotated with the `test` attribute that returns `()` can also be annotated with the `should_panic` attribute. diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index ebbb8af..bce1b8a 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -13,7 +13,7 @@ r[attributes.type-system.non_exhaustive.intro] The *`non_exhaustive` attribute* indicates that a type or variant may have more fields or variants added in the future. -r[attributes.type-system.non_exhaustive.restriction] +r[attributes.type-system.non_exhaustive.application] It can be applied to [`struct`s][struct], [`enum`s][enum], and `enum` variants. r[attributes.type-system.non_exhaustive.syntax] From 8ce2c5aaa5293598750738737d7686906fca6779 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:05:14 -0400 Subject: [PATCH 142/189] Add identifiers to behaviour-considered-undefined.md --- src/behavior-considered-undefined.md | 105 ++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 11 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 2d252ed..6ab4887 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -1,29 +1,49 @@ ## Behavior considered undefined +r[undefined] + +r[undefined.general] Rust code is incorrect if it exhibits any of the behaviors in the following list. This includes code within `unsafe` blocks and `unsafe` functions. `unsafe` only means that avoiding undefined behavior is on the programmer; it does not change anything about the fact that Rust programs must never cause undefined behavior. +r[undefined.soundness] It is the programmer's responsibility when writing `unsafe` code to ensure that any safe code interacting with the `unsafe` code cannot trigger these behaviors. `unsafe` code that satisfies this property for any safe client is called *sound*; if `unsafe` code can be misused by safe code to exhibit undefined behavior, it is *unsound*. -> [!WARNING] -> The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust's semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. We also reserve the right to make some of the behavior in that list defined in the future. In other words, this list does not say that anything will *definitely* always be undefined in all future Rust version (but we might make such commitments for some list items in the future). -> -> Please read the [Rustonomicon] before writing unsafe code. +
    + +***Warning:*** The following list is not exhaustive; it may grow or shrink. +There is no formal model of Rust's semantics for what is and is not allowed in +unsafe code, so there may be more behavior considered unsafe. We also reserve +the right to make some of the behavior in that list defined in the future. In +other words, this list does not say that anything will *definitely* always be +undefined in all future Rust version (but we might make such commitments for +some list items in the future). + +Please read the [Rustonomicon] before writing unsafe code. +
    + +r[undefined.race] * Data races. + +r[undefined.pointer-access] * Accessing (loading from or storing to) a place that is [dangling] or [based on a misaligned pointer]. + +r[undefined.place-projection] * Performing a place projection that violates the requirements of [in-bounds pointer arithmetic](pointer#method.offset). A place projection is a [field expression][project-field], a [tuple index expression][project-tuple], or an [array/slice index expression][project-slice]. + +r[undefined.alias] * Breaking the [pointer aliasing rules]. `Box`, `&mut T` and `&T` follow LLVM’s scoped [noalias] model, except if the `&T` contains an [`UnsafeCell`]. References and boxes must not be [dangling] while they are @@ -40,6 +60,8 @@ undefined behavior, it is *unsound*. All this also applies when values of these types are passed in a (nested) field of a compound type, but not behind pointer indirections. + +r[undefined.immutable] * Mutating immutable bytes. All bytes reachable through a [const-promoted] expression are immutable, as well as bytes reachable through borrows in `static` and `const` initializers that have been [lifetime-extended] to `'static`. The bytes owned by an immutable binding or immutable `static` are immutable, unless those bytes are part of an [`UnsafeCell`]. @@ -47,16 +69,28 @@ undefined behavior, it is *unsound*. Moreover, the bytes [pointed to] by a shared reference, including transitively through other references (both shared and mutable) and `Box`es, are immutable; transitivity includes those references stored in fields of compound types. A mutation is any write of more than 0 bytes which overlaps with any of the relevant bytes (even if that write does not change the memory contents). + +r[undefined.intrinsic] * Invoking undefined behavior via compiler intrinsics. + +r[undefined.target-feature] * Executing code compiled with platform features that the current platform does not support (see [`target_feature`]), *except* if the platform explicitly documents this to be safe. + +r[undefined.call] * Calling a function with the wrong call ABI or unwinding from a function with the wrong unwind ABI. + +r[undefined.invalid] * Producing an [invalid value][invalid-values]. "Producing" a value happens any time a value is assigned to or read from a place, passed to a function/primitive operation or returned from a function/primitive operation. + +r[undefined.asm] * Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. + +r[undefined.const-transmute-ptr2int] * **In [const context](const_eval.md#const-context)**: transmuting or otherwise reinterpreting a pointer (reference, raw pointer, or function pointer) into some allocated object as a non-pointer type (such as integers). @@ -71,11 +105,15 @@ undefined behavior, it is *unsound*. ### Pointed-to bytes +r[undefined.pointed-to] The span of bytes a pointer or reference "points to" is determined by the pointer value and the size of the pointee type (using `size_of_val`). ### Places based on misaligned pointers [based on a misaligned pointer]: #places-based-on-misaligned-pointers +r[undefined.misaligned] + +r[undefined.misaligned.general] A place is said to be "based on a misaligned pointer" if the last `*` projection during place computation was performed on a pointer that was not aligned for its type. (If there is no `*` projection in the place expression, then this is @@ -93,12 +131,20 @@ alignment 1). In other words, the alignment requirement derives from the type of the pointer that was dereferenced, *not* the type of the field that is being accessed. -Note that a place based on a misaligned pointer only leads to undefined behavior -when it is loaded from or stored to. `&raw const`/`&raw mut` on such a place -is allowed. `&`/`&mut` on a place requires the alignment of the field type (or +r[undefined.misaligned.load-store] +Note that a place based on a misaligned pointer only leads to Undefined Behavior +when it is loaded from or stored to. + +r[undefined.misaligned.raw] +`&raw const`/`&raw mut` on such a place is allowed. + +r[undefined.misaligned.reference] +`&`/`&mut` on a place requires the alignment of the field type (or else the program would be "producing an invalid value"), which generally is a -less restrictive requirement than being based on an aligned pointer. Taking a -reference will lead to a compiler error in cases where the field type might be +less restrictive requirement than being based on an aligned pointer. + +r[undefined.misaligned.packed] +Taking a reference will lead to a compiler error in cases where the field type might be more aligned than the type that contains it, i.e., `repr(packed)`. This means that being based on an aligned pointer is always sufficient to ensure that the new reference is aligned, but it is not always necessary. @@ -106,43 +152,77 @@ new reference is aligned, but it is not always necessary. ### Dangling pointers [dangling]: #dangling-pointers +r[undefined.dangling] + +r[undefined.dangling.general] A reference/pointer is "dangling" if not all of the bytes it [points to] are part of the same live allocation (so in particular they all have to be part of *some* allocation). +r[undefined.dangling.zero-size] If the size is 0, then the pointer is trivially never "dangling" (even if it is a null pointer). +r[undefined.dangling.dynamic-size] Note that dynamically sized types (such as slices and strings) point to their -entire range, so it is important that the length metadata is never too large. In -particular, the dynamic size of a Rust value (as determined by `size_of_val`) +entire range, so it is important that the length metadata is never too large. + +r[undefined.dangling.alloc-limit] +In particular, the dynamic size of a Rust value (as determined by `size_of_val`) must never exceed `isize::MAX`, since it is impossible for a single allocation to be larger than `isize::MAX`. ### Invalid values [invalid-values]: #invalid-values +r[undefined.validity] + + +r[undefined.validity.general] The Rust compiler assumes that all values produced during program execution are "valid", and producing an invalid value is hence immediate UB. Whether a value is valid depends on the type: + +r[undefined.validity.bool] * A [`bool`] value must be `false` (`0`) or `true` (`1`). + +r[undefined.validity.fn-pointer] * A `fn` pointer value must be non-null. + +r[undefined.validity.char] * A `char` value must not be a surrogate (i.e., must not be in the range `0xD800..=0xDFFF`) and must be equal to or less than `char::MAX`. + +r[undefined.validity.never] * A `!` value must never exist. + +r[undefined.validity.scalar] * An integer (`i*`/`u*`), floating point value (`f*`), or raw pointer must be initialized, i.e., must not be obtained from [uninitialized memory][undef]. + + +r[undefined.validity.str] * A `str` value is treated like `[u8]`, i.e. it must be initialized. + +r[undefined.validity.enum] * An `enum` must have a valid discriminant, and all fields of the variant indicated by that discriminant must be valid at their respective type. + +r[undefined.validity.struct] * A `struct`, tuple, and array requires all fields/elements to be valid at their respective type. + +r[undefined.validity.union] * For a `union`, the exact validity requirements are not decided yet. Obviously, all values that can be created entirely in safe code are valid. If the union has a zero-sized field, then every possible value is valid. Further details are [still being debated](https://github.com/rust-lang/unsafe-code-guidelines/issues/438). + +r[undefined.validity.reference-box] * A reference or [`Box`] must be aligned, it cannot be [dangling], and it must point to a valid value (in case of dynamically sized types, using the actual dynamic type of the pointee as determined by the metadata). Note that the last point (about pointing to a valid value) remains a subject of some debate. + +r[undefined.validity.wide] * The metadata of a wide reference, [`Box`], or raw pointer must match the type of the unsized tail: * `dyn Trait` metadata must be a pointer to a compiler-generated vtable for `Trait`. @@ -150,12 +230,15 @@ Whether a value is valid depends on the type: * Slice (`[T]`) metadata must be a valid `usize`. Furthermore, for wide references and [`Box`], slice metadata is invalid if it makes the total size of the pointed-to value bigger than `isize::MAX`. + +r[undefined.validity.valid-range] * If a type has a custom range of a valid values, then a valid value must be in that range. In the standard library, this affects [`NonNull`] and [`NonZero`]. > **Note**: `rustc` achieves this with the unstable > `rustc_layout_scalar_valid_range_*` attributes. +r[undefined.validity.undef] **Note:** Uninitialized memory is also implicitly invalid for any type that has a restricted set of valid values. In other words, the only cases in which reading uninitialized memory is permitted are inside `union`s and in "padding" From a1ca311b947077d2855b3f530257792d0cd8d2b3 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 19:53:06 -0400 Subject: [PATCH 143/189] Remove double line breaks from behaviour-considered-undefined --- src/behavior-considered-undefined.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 6ab4887..424ef22 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -177,7 +177,6 @@ to be larger than `isize::MAX`. r[undefined.validity] - r[undefined.validity.general] The Rust compiler assumes that all values produced during program execution are "valid", and producing an invalid value is hence immediate UB. @@ -200,7 +199,6 @@ r[undefined.validity.scalar] * An integer (`i*`/`u*`), floating point value (`f*`), or raw pointer must be initialized, i.e., must not be obtained from [uninitialized memory][undef]. - r[undefined.validity.str] * A `str` value is treated like `[u8]`, i.e. it must be initialized. @@ -244,7 +242,6 @@ a restricted set of valid values. In other words, the only cases in which reading uninitialized memory is permitted are inside `union`s and in "padding" (the gaps between the fields of a type). - [`bool`]: types/boolean.md [`const`]: items/constant-items.md [noalias]: http://llvm.org/docs/LangRef.html#noalias From d3a87834241d48e4471109e47a674cdea0df1998 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:28:31 -0400 Subject: [PATCH 144/189] Add identifier syntax to conditional-compilation.md --- src/conditional-compilation.md | 141 ++++++++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 10 deletions(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index f73f835..e6e26b2 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -1,5 +1,9 @@ # Conditional compilation +r[cfg] + + +r[cfg.syntax] > **Syntax**\ > _ConfigurationPredicate_ :\ >       _ConfigurationOption_\ @@ -22,30 +26,62 @@ > _ConfigurationPredicateList_\ >    _ConfigurationPredicate_ (`,` _ConfigurationPredicate_)\* `,`? -*Conditionally compiled source code* is source code that is compiled only under certain conditions. Source code can be made conditionally compiled using the [`cfg`] and [`cfg_attr`] [attributes] and the built-in [`cfg` macro]. Whether to compile can depend on the target architecture of the compiled crate, arbitrary values passed to the compiler, and other things further described below. +r[cfg.general] +*Conditionally compiled source code* is source code that is compiled only under certain conditions. + +r[cfg.attributes-macro] +Source code can be made conditionally compiled using the [`cfg`] and [`cfg_attr`] [attributes] and the built-in [`cfg` macro]. +r[cfg.conditional] +Whether to compile can depend on the target architecture of the compiled crate, arbitrary values passed to the compiler, and other things further described below. + +r[cfg.predicate] Each form of conditional compilation takes a _configuration predicate_ that evaluates to true or false. The predicate is one of the following: +r[cfg.predicate.option] * A configuration option. The predicate is true if the option is set, and false if it is unset. + +r[cfg.predicate.all] * `all()` with a comma-separated list of configuration predicates. It is true if all of the given predicates are true, or if the list is empty. + +r[cfg.predicate.any] * `any()` with a comma-separated list of configuration predicates. It is true if at least one of the given predicates is true. If there are no predicates, it is false. + +r[cfg.predicate.not] * `not()` with a configuration predicate. It is true if its predicate is false and false if its predicate is true. +r[cfg.option-spec] _Configuration options_ are either names or key-value pairs, and are either set or unset. + +r[cfg.option-name] Names are written as a single identifier, such as `unix`. + +r[cfg.option-key-value] Key-value pairs are written as an identifier, `=`, and then a string, such as `target_arch = "x86_64"`. > **Note**: Whitespace around the `=` is ignored, so `foo="bar"` and `foo = "bar"` are equivalent. +r[cfg.option-key-uniqueness] Keys do not need to be unique. For example, both `feature = "std"` and `feature = "serde"` can be set at the same time. ## Set Configuration Options +r[cfg.options.set] + + +r[cfg.options.general] Which configuration options are set is determined statically during the -compilation of the crate. Some options are _compiler-set_ based on data -about the compilation. Other options are _arbitrarily-set_ based on input -passed to the compiler outside of the code. It is not possible to set a +compilation of the crate. + +r[cfg.options.target] +Some options are _compiler-set_ based on data about the compilation. + +r[cfg.options.other] +Other options are _arbitrarily-set_ based on input passed to the compiler outside of the code. + +r[cfg.options.crate] +It is not possible to set a configuration option from within the source code of the crate being compiled. > **Note**: For `rustc`, arbitrary-set configuration options are set using the @@ -60,10 +96,15 @@ configuration option from within the source code of the crate being compiled. ### `target_arch` +r[cfg.target_arch] + + +r[cfg.target_arch.gen] Key-value option set once with the target's CPU architecture. The value is similar to the first element of the platform's target triple, but not identical. +r[cfg.target_arch.values] Example values: * `"x86"` @@ -76,9 +117,14 @@ Example values: ### `target_feature` +r[cfg.target_feature] + + +r[cfg.target_feature.general] Key-value option set for each platform feature available for the current compilation target. +r[cfg.target_feature.values] Example values: * `"avx"` @@ -90,14 +136,22 @@ Example values: * `"sse4.1"` See the [`target_feature` attribute] for more details on the available -features. An additional feature of `crt-static` is available to the +features. + +r[cfg.target_feature.crt_static] +An additional feature of `crt-static` is available to the `target_feature` option to indicate that a [static C runtime] is available. ### `target_os` +r[cfg.target_os] + + +r[cfg.target_os.general] Key-value option set once with the target's operating system. This value is similar to the second and third element of the platform's target triple. +r[cfg.target_os.values] Example values: * `"windows"` @@ -113,10 +167,15 @@ Example values: ### `target_family` +r[cfg.target_family] + + +r[cfg.target_family.general] Key-value option providing a more generic description of a target, such as the family of the operating systems or architectures that the target generally falls into. Any number of `target_family` key-value pairs can be set. +r[cfg.target_family.values] Example values: * `"unix"` @@ -126,11 +185,17 @@ Example values: ### `unix` and `windows` -`unix` is set if `target_family = "unix"` is set and `windows` is set if -`target_family = "windows"` is set. +r[cfg.target_family.unix] +`unix` is set if `target_family = "unix"` is set. + +r[cfg.target_family.windows] +`windows` is set if `target_family = "windows"` is set. ### `target_env` +r[cfg.target_env] + +r[cfg.target_env.values] Key-value option set with further disambiguating information about the target platform with information about the ABI or `libc` used. For historical reasons, this value is only defined as not the empty-string when actually needed for @@ -139,6 +204,7 @@ empty. This value is similar to the fourth element of the platform's target triple. One difference is that embedded ABIs such as `gnueabihf` will simply define `target_env` as `"gnu"`. +r[cfg.target_env.values] Example values: * `""` @@ -149,12 +215,19 @@ Example values: ### `target_abi` +r[cfg.target_abi] + + +r[cfg.target_env.general] Key-value option set to further disambiguate the `target_env` with information -about the target ABI. For historical reasons, -this value is only defined as not the empty-string when actually needed for -disambiguation. Thus, for example, on many GNU platforms, this value will be +about the target ABI. + +r[cfg.target_env.disambiguation] +For historical reasons, this value is only defined as not the empty-string when actually + needed for disambiguation. Thus, for example, on many GNU platforms, this value will be empty. +r[cfg.target_env.values] Example values: * `""` @@ -166,13 +239,19 @@ Example values: ### `target_endian` +r[cfg.target_endian] Key-value option set once with either a value of "little" or "big" depending on the endianness of the target's CPU. ### `target_pointer_width` +r[cfg.target_poitner_width] + + +r[cfg.target_pointer_width.general] Key-value option set once with the target's pointer width in bits. +r[cfg.target_pointer_width.values] Example values: * `"16"` @@ -181,8 +260,13 @@ Example values: ### `target_vendor` +r[cfg.target_vendor] + + +r[cfg.target_vendor.general] Key-value option set once with the vendor of the target. +r[cfg.target_vendor.values] Example values: * `"apple"` @@ -192,12 +276,19 @@ Example values: ### `target_has_atomic` +r[cfg.target_has_atomic] + + +r[cfg.target_has_atomic.general] Key-value option set for each bit width that the target supports atomic loads, stores, and compare-and-swap operations. +r[cfg.target_has_atomic.stdlib] When this cfg is present, all of the stable [`core::sync::atomic`] APIs are available for the relevant atomic width. + +r[cfg.target_has_atomic.values] Possible values: * `"8"` @@ -209,11 +300,15 @@ Possible values: ### `test` +r[cfg.test] + Enabled when compiling the test harness. Done with `rustc` by using the [`--test`] flag. See [Testing] for more on testing support. ### `debug_assertions` +r[cfg.debug_assertions] + Enabled by default when compiling without optimizations. This can be used to enable extra debugging code in development but not in production. For example, it controls the behavior of the standard library's @@ -221,13 +316,20 @@ production. For example, it controls the behavior of the standard library's ### `proc_macro` +r[cfg.proc_macro] + Set when the crate being compiled is being compiled with the `proc_macro` [crate type]. ### `panic` +r[cfg.panic] + + +r[cfg.panic.general] Key-value option set depending on the panic strategy. Note that more values may be added in the future. +r[cfg.panic.values] Example values: * `"abort"` @@ -237,20 +339,28 @@ Example values: ### The `cfg` attribute +r[cfg.attr] + + +r[cfg.attr.syntax] > **Syntax**\ > _CfgAttrAttribute_ :\ >    `cfg` `(` _ConfigurationPredicate_ `)` +r[cfg.attr.general] The `cfg` [attribute] conditionally includes the thing it is attached to based on a configuration predicate. +r[cfg.attr.syntax-explanation] It is written as `cfg`, `(`, a configuration predicate, and finally `)`. +r[cfg.attr.effect] If the predicate is true, the thing is rewritten to not have the `cfg` attribute on it. If the predicate is false, the thing is removed from the source code. +r[cfg.attr.crate-level-attrs] When a crate-level `cfg` has a false predicate, the behavior is slightly different: any crate attributes preceding the `cfg` are kept, and any crate attributes following the `cfg` are removed. This allows `#![no_std]` and @@ -293,10 +403,15 @@ fn when_unwinding() { ``` +r[cfg.attr.restriction] The `cfg` attribute is allowed anywhere attributes are allowed. ### The `cfg_attr` attribute +r[cfg.cfg_attr] + + +r[cfg.cfg_attr.syntax] > **Syntax**\ > _CfgAttrAttribute_ :\ >    `cfg_attr` `(` _ConfigurationPredicate_ `,` _CfgAttrs_? `)` @@ -304,9 +419,12 @@ The `cfg` attribute is allowed anywhere attributes are allowed. > _CfgAttrs_ :\ >    [_Attr_] (`,` [_Attr_])\* `,`? + +r[cfg.cfg_attr.syntax] The `cfg_attr` [attribute] conditionally includes [attributes] based on a configuration predicate. +r[cfg.cfg_attr.behaviour] When the configuration predicate is true, this attribute expands out to the attributes listed after the predicate. For example, the following module will either be found at `linux.rs` or `windows.rs` based on the target. @@ -318,6 +436,7 @@ either be found at `linux.rs` or `windows.rs` based on the target. mod os; ``` +r[cfg.cfg_attr.attribute-list] Zero, one, or more attributes may be listed. Multiple attributes will each be expanded into separate attributes. For example: @@ -337,10 +456,12 @@ fn bewitched() {} > is valid. This example would be equivalent to > `#[cfg_attr(all(target_os = "linux", feature ="multithreaded"), some_other_attribute)]`. +r[cfg.cfg_attr.restriction] The `cfg_attr` attribute is allowed anywhere attributes are allowed. ### The `cfg` macro +r[cfg.macro] The built-in `cfg` macro takes in a single configuration predicate and evaluates to the `true` literal when the predicate is true and the `false` literal when it is false. From f099fedc2b55af3e56d0659e6c20cff5001013ff Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:33:31 -0400 Subject: [PATCH 145/189] Fix duplicate key cfg.target_env.general --- src/conditional-compilation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index e6e26b2..fdedb43 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -195,7 +195,7 @@ r[cfg.target_family.windows] r[cfg.target_env] -r[cfg.target_env.values] +r[cfg.target_env.general] Key-value option set with further disambiguating information about the target platform with information about the ABI or `libc` used. For historical reasons, this value is only defined as not the empty-string when actually needed for From 6a8863a0a0f5bf69cb506ae18c56684e19c2399c Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:36:54 -0400 Subject: [PATCH 146/189] Use proper keys in cfg.target_abi --- src/conditional-compilation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index fdedb43..bff5483 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -218,16 +218,16 @@ Example values: r[cfg.target_abi] -r[cfg.target_env.general] +r[cfg.target_abi.general] Key-value option set to further disambiguate the `target_env` with information about the target ABI. -r[cfg.target_env.disambiguation] +r[cfg.target_abi.disambiguation] For historical reasons, this value is only defined as not the empty-string when actually needed for disambiguation. Thus, for example, on many GNU platforms, this value will be empty. -r[cfg.target_env.values] +r[cfg.target_abi.values] Example values: * `""` From e1b12cc3279d968ccde87302e1697cf85248e8f3 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 7 Aug 2024 22:38:35 -0400 Subject: [PATCH 147/189] I'm 0/3 on duplicate attributes, 4th times the charm? --- src/conditional-compilation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index bff5483..ea28d48 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -420,7 +420,7 @@ r[cfg.cfg_attr.syntax] >    [_Attr_] (`,` [_Attr_])\* `,`? -r[cfg.cfg_attr.syntax] +r[cfg.cfg_attr.general] The `cfg_attr` [attribute] conditionally includes [attributes] based on a configuration predicate. From 131f22439b16e951dd0b81fb43043a2a3be32578 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 19:50:39 -0400 Subject: [PATCH 148/189] Remove double linebreaks from conditional-compilation.md --- src/conditional-compilation.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index ea28d48..2a4db8d 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -2,7 +2,6 @@ r[cfg] - r[cfg.syntax] > **Syntax**\ > _ConfigurationPredicate_ :\ @@ -69,7 +68,6 @@ Keys do not need to be unique. For example, both `feature = "std"` and `feature r[cfg.options.set] - r[cfg.options.general] Which configuration options are set is determined statically during the compilation of the crate. @@ -98,7 +96,6 @@ configuration option from within the source code of the crate being compiled. r[cfg.target_arch] - r[cfg.target_arch.gen] Key-value option set once with the target's CPU architecture. The value is similar to the first element of the platform's target triple, but not @@ -119,7 +116,6 @@ Example values: r[cfg.target_feature] - r[cfg.target_feature.general] Key-value option set for each platform feature available for the current compilation target. @@ -146,7 +142,6 @@ An additional feature of `crt-static` is available to the r[cfg.target_os] - r[cfg.target_os.general] Key-value option set once with the target's operating system. This value is similar to the second and third element of the platform's target triple. @@ -169,7 +164,6 @@ Example values: r[cfg.target_family] - r[cfg.target_family.general] Key-value option providing a more generic description of a target, such as the family of the operating systems or architectures that the target generally falls into. Any number of @@ -217,7 +211,6 @@ Example values: r[cfg.target_abi] - r[cfg.target_abi.general] Key-value option set to further disambiguate the `target_env` with information about the target ABI. @@ -247,7 +240,6 @@ on the endianness of the target's CPU. r[cfg.target_poitner_width] - r[cfg.target_pointer_width.general] Key-value option set once with the target's pointer width in bits. @@ -262,7 +254,6 @@ Example values: r[cfg.target_vendor] - r[cfg.target_vendor.general] Key-value option set once with the vendor of the target. @@ -278,7 +269,6 @@ Example values: r[cfg.target_has_atomic] - r[cfg.target_has_atomic.general] Key-value option set for each bit width that the target supports atomic loads, stores, and compare-and-swap operations. @@ -325,7 +315,6 @@ Set when the crate being compiled is being compiled with the `proc_macro` r[cfg.panic] - r[cfg.panic.general] Key-value option set depending on the panic strategy. Note that more values may be added in the future. @@ -341,7 +330,6 @@ Example values: r[cfg.attr] - r[cfg.attr.syntax] > **Syntax**\ > _CfgAttrAttribute_ :\ @@ -410,7 +398,6 @@ The `cfg` attribute is allowed anywhere attributes are allowed. r[cfg.cfg_attr] - r[cfg.cfg_attr.syntax] > **Syntax**\ > _CfgAttrAttribute_ :\ @@ -419,7 +406,6 @@ r[cfg.cfg_attr.syntax] > _CfgAttrs_ :\ >    [_Attr_] (`,` [_Attr_])\* `,`? - r[cfg.cfg_attr.general] The `cfg_attr` [attribute] conditionally includes [attributes] based on a configuration predicate. From abe3986aa2145d2103fa37296f1e5c45b014c5d9 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 13 Aug 2024 14:43:47 -0400 Subject: [PATCH 149/189] Add identifiers to const_eval.md --- src/const_eval.md | 87 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/src/const_eval.md b/src/const_eval.md index eca2530..888c5b5 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -1,68 +1,134 @@ # Constant evaluation +r[const-eval] +r[const-eval.general] Constant evaluation is the process of computing the result of [expressions] during compilation. Only a subset of all expressions can be evaluated at compile-time. ## Constant expressions +r[const-eval.const-expr] + +r[const-eval.const-expr.general] Certain forms of expressions, called constant expressions, can be evaluated at -compile time. In [const contexts](#const-context), these are the only allowed -expressions, and are always evaluated at compile time. In other places, such as -[let statements], constant expressions *may* -be, but are not guaranteed to be, evaluated at compile time. Behaviors such as -out of bounds [array indexing] or [overflow] are compiler errors if the value +compile time. + +r[const-eval.const-expr.const-context] +In [const contexts](#const-context), these are the only allowed +expressions, and are always evaluated at compile time. + +r[const-eval.const-expr.runtime-context] +In other places, such as [let statements], constant expressions *may* be, but are not guaranteed to be, evaluated at compile time. + +r[const-eval.const-expr.error] +Behaviors such as out of bounds [array indexing] or [overflow] are compiler errors if the value must be evaluated at compile time (i.e. in const contexts). Otherwise, these behaviors are warnings, but will likely panic at run-time. + +r[const-eval.const-expr.list] The following expressions are constant expressions, so long as any operands are also constant expressions and do not cause any [`Drop::drop`][destructors] calls to be run. +r[const-eval.const-expr.literal] * [Literals]. + +r[const-eval.const-expr.parameter] * [Const parameters]. + +r[const-eval.const-expr.path-item] * [Paths] to [functions] and [constants]. Recursively defining constants is not allowed. + +r[const-eval.const-expr.path-static] * Paths to [statics]. These are only allowed within the initializer of a static. + +r[const-eval.const-expr.tuple] * [Tuple expressions]. + +r[const-eval.const-expr.array] * [Array expressions]. + +r[const-eval.const-expr.constructor] * [Struct] expressions. + +r[const-eval.const-expr.block] * [Block expressions], including `unsafe` and `const` blocks. * [let statements] and thus irrefutable [patterns], including mutable bindings * [assignment expressions] * [compound assignment expressions] * [expression statements] + +r[const-eval.const-expr.field] * [Field] expressions. + +r[const-eval.const-expr.index] * Index expressions, [array indexing] or [slice] with a `usize`. + +r[const-eval.const-expr.range] * [Range expressions]. + +r[const-eval.const-expr.closure] * [Closure expressions] which don't capture variables from the environment. + +r[const-eval.const-expr.builtin-arith-logic] * Built-in [negation], [arithmetic], [logical], [comparison] or [lazy boolean] operators used on integer and floating point types, `bool`, and `char`. + +r[const-eval.const-expr.borrows] * All forms of [borrow]s, including raw borrows, with one limitation: mutable borrows and shared borrows to values with interior mutability are only allowed to refer to *transient* places. A place is *transient* if its lifetime is strictly contained inside the current [const context]. -* The [dereference operator]. + +r[const-eval.const-expr.deref] +* The [dereference operator] except for raw pointers. + +r[const-eval.const-expr.group] + * [Grouped] expressions. + +r[const-eval.const-expr.cast] * [Cast] expressions, except * pointer to address casts and * function pointer to address casts. + +r[const-eval.const-expr.const-fn] * Calls of [const functions] and const methods. + +r[const-eval.const-expr.loop] * [loop], [while] and [`while let`] expressions. + +r[const-eval.const-expr.if-match] * [if], [`if let`] and [match] expressions. ## Const context [const context]: #const-context +r[const-eval.const-context] + + +r[const-eval.const-context.general] A _const context_ is one of the following: +r[const-eval.const-context.array-length] * [Array type length expressions] + +r[const-eval.const-context.repeat-length] * [Array repeat length expressions][array expressions] + +r[const-eval.const-context.init] * The initializer of * [constants] * [statics] * [enum discriminants] + +r[const-eval.const-context.generic] * A [const generic argument] + +r[const-eval.const-context.block] * A [const block] Const contexts that are used as parts of types (array type and repeat length @@ -73,10 +139,17 @@ generics. ## Const Functions -A _const fn_ is a function that one is permitted to call from a const context. Declaring a function +r[const-eval.const-fn] + +r[const-eval.const-fn.general] +A _const fn_ is a function that one is permitted to call from a const context. + +r[const-eval.const-fn.usage] +Declaring a function `const` has no effect on any existing uses, it only restricts the types that arguments and the return type may use, and restricts the function body to constant expressions. +r[const-eval.const-fn.const-context] When called from a const context, the function is interpreted by the compiler at compile time. The interpretation happens in the environment of the compilation target and not the host. So `usize` is From b72d5191e312b8f698697743897f861d32edd186 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 21 Aug 2024 19:50:04 -0400 Subject: [PATCH 150/189] Remove double line break from const_eval --- src/const_eval.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/const_eval.md b/src/const_eval.md index 888c5b5..c7a3bca 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -26,7 +26,6 @@ Behaviors such as out of bounds [array indexing] or [overflow] are compiler erro must be evaluated at compile time (i.e. in const contexts). Otherwise, these behaviors are warnings, but will likely panic at run-time. - r[const-eval.const-expr.list] The following expressions are constant expressions, so long as any operands are also constant expressions and do not cause any [`Drop::drop`][destructors] calls @@ -109,7 +108,6 @@ r[const-eval.const-expr.if-match] r[const-eval.const-context] - r[const-eval.const-context.general] A _const context_ is one of the following: From b440726d98260dc0dc22be91d53cbb9966ea3da8 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 21 Oct 2024 12:31:42 -0400 Subject: [PATCH 151/189] Update src/trait-bounds.md Co-authored-by: Travis Cross --- src/trait-bounds.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 530e978..67df956 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -52,7 +52,7 @@ certain common cases: `trait A { type B: Copy; }` is equivalent to `trait A where Self::B: Copy { type B; }`. -r[bound.satisfication] +r[bound.satisfaction] Bounds on an item must be satisfied when using the item. When type checking and borrow checking a generic item, the bounds can be used to determine that a trait is implemented for a type. For example, given `Ty: Trait` From 785f2efe396b0435f723747e928d9b36705b271d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 26 Sep 2024 10:25:39 -0400 Subject: [PATCH 152/189] Add identifier syntax to macro-ambiguity.md --- src/macro-ambiguity.md | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/macro-ambiguity.md b/src/macro-ambiguity.md index d8ca480..b29d6ce 100644 --- a/src/macro-ambiguity.md +++ b/src/macro-ambiguity.md @@ -1,11 +1,16 @@ # Appendix: Macro Follow-Set Ambiguity Formal Specification +r[macro.ambiguity] + This page documents the formal specification of the follow rules for [Macros By Example]. They were originally specified in [RFC 550], from which the bulk of this text is copied, and expanded upon in subsequent RFCs. ## Definitions & Conventions +r[macro.ambiguity.conventions] + +r[macro.ambiguity.conventions.defs] - `macro`: anything invokable as `foo!(...)` in source code. - `MBE`: macro-by-example, a macro defined by `macro_rules`. - `matcher`: the left-hand-side of a rule in a `macro_rules` invocation, or a @@ -46,11 +51,13 @@ macro_rules! i_am_an_mbe { } ``` +r[macro.ambiguity.convention.matcher] `(start $foo:expr $($i:ident),* end)` is a matcher. The whole matcher is a delimited sequence (with open- and close-delimiters `(` and `)`), and `$foo` and `$i` are simple NT's with `expr` and `ident` as their respective fragment specifiers. +r[macro.ambiguity.convention.complex-nt] `$(i:ident),*` is *also* an NT; it is a complex NT that matches a comma-separated repetition of identifiers. The `,` is the separator token for the complex NT; it occurs in between each pair of elements (if any) of the @@ -65,16 +72,19 @@ token. proper nesting of token tree structure and correct matching of open- and close-delimiters.) +r[macro.ambiguity.convention.vars] We will tend to use the variable "M" to stand for a matcher, variables "t" and "u" for arbitrary individual tokens, and the variables "tt" and "uu" for arbitrary token trees. (The use of "tt" does present potential ambiguity with its additional role as a fragment specifier; but it will be clear from context which interpretation is meant.) +r[macro.ambiguity.convention.set] "SEP" will range over separator tokens, "OP" over the repetition operators `*`, `+`, and `?`, "OPEN"/"CLOSE" over matching token pairs surrounding a delimited sequence (e.g. `[` and `]`). +r[macro.ambiguity.sequence-vars] Greek letters "α" "β" "γ" "δ" stand for potentially empty token-tree sequences. (However, the Greek letter "ε" (epsilon) has a special role in the presentation and does not stand for a token-tree sequence.) @@ -101,6 +111,9 @@ purposes of the formalism, we will treat `$v:vis` as actually being ### The Matcher Invariants +r[macro.ambiguity.invariant] + +r[macro.ambiguity.invariant.list] To be valid, a matcher must meet the following three invariants. The definitions of FIRST and FOLLOW are described later. @@ -112,18 +125,21 @@ of FIRST and FOLLOW are described later. 1. For an unseparated complex NT in a matcher, `M = ... $(tt ...) OP ...`, if OP = `*` or `+`, we must have FOLLOW(`tt ...`) ⊇ FIRST(`tt ...`). +r[macro.ambiguity.invariant.follow-matcher] The first invariant says that whatever actual token that comes after a matcher, if any, must be somewhere in the predetermined follow set. This ensures that a legal macro definition will continue to assign the same determination as to where `... tt` ends and `uu ...` begins, even as new syntactic forms are added to the language. +r[macro.ambiguity.invariant.separated-complex-nt] The second invariant says that a separated complex NT must use a separator token that is part of the predetermined follow set for the internal contents of the NT. This ensures that a legal macro definition will continue to parse an input fragment into the same delimited sequence of `tt ...`'s, even as new syntactic forms are added to the language. +r[macro.ambiguity.invariant.unseparated-complex-nt] The third invariant says that when we have a complex NT that can match two or more copies of the same thing with no separation in between, it must be permissible for them to be placed next to each other as per the first invariant. @@ -137,6 +153,9 @@ invalid in a future edition of Rust. See the [tracking issue].** ### FIRST and FOLLOW, informally +r[macro.ambiguity.sets] + +r[macro.ambiguity.sets.intro] A given matcher M maps to three sets: FIRST(M), LAST(M) and FOLLOW(M). Each of the three sets is made up of tokens. FIRST(M) and LAST(M) may also @@ -145,12 +164,15 @@ can match the empty fragment. (But FOLLOW(M) is always just a set of tokens.) Informally: +r[macro.ambiguity.sets.first] * FIRST(M): collects the tokens potentially used first when matching a fragment to M. +r[macro.ambiguity.sets.last] * LAST(M): collects the tokens potentially used last when matching a fragment to M. +r[macro.ambiguity.sets.follow] * FOLLOW(M): the set of tokens allowed to follow immediately after some fragment matched by M. @@ -163,6 +185,7 @@ Informally: * The concatenation α β γ δ is a parseable Rust program. +r[macro.ambiguity.sets.universe] We use the shorthand ANYTOKEN to denote the set of all tokens (including simple NTs). For example, if any token is legal after a matcher M, then FOLLOW(M) = ANYTOKEN. @@ -174,18 +197,27 @@ definitions.) ### FIRST, LAST +r[macro.ambiguity.sets.def] + +r[macro.ambiguity.sets.def.intro] Below are formal inductive definitions for FIRST and LAST. +r[macro.ambiguity.sets.def.notation] "A ∪ B" denotes set union, "A ∩ B" denotes set intersection, and "A \ B" denotes set difference (i.e. all elements of A that are not present in B). #### FIRST +r[macro.ambiguity.sets.def.first] + +r[macro.ambiguity.sets.def.first.intro] FIRST(M) is defined by case analysis on the sequence M and the structure of its first token-tree (if any): +r[macro.ambiguity.sets.def.first.epsilon] * if M is the empty sequence, then FIRST(M) = { ε }, +r[macro.ambiguity.sets.def.first.token] * if M starts with a token t, then FIRST(M) = { t }, (Note: this covers the case where M starts with a delimited token-tree @@ -195,6 +227,7 @@ first token-tree (if any): (Note: this critically relies on the property that no simple NT matches the empty fragment.) +r[macro.ambiguity.sets.def.first.complex] * Otherwise, M is a token-tree sequence starting with a complex NT: `M = $( tt ... ) OP α`, or `M = $( tt ... ) SEP OP α`, (where `α` is the (potentially empty) sequence of token trees for the rest of the matcher). @@ -229,12 +262,18 @@ with respect to \varepsilon as well. #### LAST +r[macro.ambiguity.sets.def.last] + +r[macro.ambiguity.sets.def.last.intro] LAST(M), defined by case analysis on M itself (a sequence of token-trees): +r[macro.ambiguity.sets.def.last.empty] * if M is the empty sequence, then LAST(M) = { ε } +r[macro.ambiguity.sets.def.last.token] * if M is a singleton token t, then LAST(M) = { t } +r[macro.ambiguity.sets.def.last.rep-star] * if M is the singleton complex NT repeating zero or more times, `M = $( tt ... ) *`, or `M = $( tt ... ) SEP *` @@ -245,6 +284,7 @@ LAST(M), defined by case analysis on M itself (a sequence of token-trees): * otherwise, the sequence `tt ...` must be non-empty; LAST(M) = LAST(`tt ...`) ∪ {ε}. +r[macro.ambiguity.sets.def.last.rep-plus] * if M is the singleton complex NT repeating one or more times, `M = $( tt ... ) +`, or `M = $( tt ... ) SEP +` @@ -255,12 +295,15 @@ LAST(M), defined by case analysis on M itself (a sequence of token-trees): * otherwise, the sequence `tt ...` must be non-empty; LAST(M) = LAST(`tt ...`) +r[macro.ambiguity.sets.def.last.rep-question] * if M is the singleton complex NT repeating zero or one time, `M = $( tt ...) ?`, then LAST(M) = LAST(`tt ...`) ∪ {ε}. +r[macro.ambiguity.sets.def.last.delim] * if M is a delimited token-tree sequence `OPEN tt ... CLOSE`, then LAST(M) = { `CLOSE` }. +r[macro.ambiguity.sets.def.last.sequence] * if M is a non-empty sequence of token-trees `tt uu ...`, * If ε ∈ LAST(`uu ...`), then LAST(M) = LAST(`tt`) ∪ (LAST(`uu ...`) \ { ε }). @@ -320,25 +363,35 @@ Here are similar examples but now for LAST. ### FOLLOW(M) +r[macro.ambiguity.sets.def.follow] + +r[macro.ambiguity.sets.def.follow.intro] Finally, the definition for FOLLOW(M) is built up as follows. pat, expr, etc. represent simple nonterminals with the given fragment specifier. +r[macro.ambiguity.sets.def.follow.pat] * FOLLOW(pat) = {`=>`, `,`, `=`, `|`, `if`, `in`}`. +r[macro.ambiguity.sets.def.follow.expr-stmt] * FOLLOW(expr) = FOLLOW(expr_2021) = FOLLOW(stmt) = {`=>`, `,`, `;`}`. +r[macro.ambiguity.sets.def.follow.ty-path] * FOLLOW(ty) = FOLLOW(path) = {`{`, `[`, `,`, `=>`, `:`, `=`, `>`, `>>`, `;`, `|`, `as`, `where`, block nonterminals}. +r[macro.ambiguity.sets.def.follow.vis] * FOLLOW(vis) = {`,`l any keyword or identifier except a non-raw `priv`; any token that can begin a type; ident, ty, and path nonterminals}. +r[macro.ambiguity.sets.def.follow.simple] * FOLLOW(t) = ANYTOKEN for any other simple token, including block, ident, tt, item, lifetime, literal and meta simple nonterminals, and all terminals. +r[macro.ambiguity.sets.def.follow.other-matcher] * FOLLOW(M), for any other M, is defined as the intersection, as t ranges over (LAST(M) \ {ε}), of FOLLOW(t). +r[macro.ambiguity.sets.def.follow.type-first] The tokens that can begin a type are, as of this writing, {`(`, `[`, `!`, `*`, `&`, `&&`, `?`, lifetimes, `>`, `>>`, `::`, any non-keyword identifier, `super`, `self`, `Self`, `extern`, `crate`, `$crate`, `_`, `for`, `impl`, `fn`, `unsafe`, From e0da1400e665ae620842ee24c56207df0c3a4cc4 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 21 Oct 2024 12:34:12 -0400 Subject: [PATCH 153/189] Fix identifiers in Definitions & Conventions section --- src/macro-ambiguity.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/macro-ambiguity.md b/src/macro-ambiguity.md index b29d6ce..ffdd796 100644 --- a/src/macro-ambiguity.md +++ b/src/macro-ambiguity.md @@ -8,9 +8,9 @@ of this text is copied, and expanded upon in subsequent RFCs. ## Definitions & Conventions -r[macro.ambiguity.conventions] +r[macro.ambiguity.convention] -r[macro.ambiguity.conventions.defs] +r[macro.ambiguity.convention.defs] - `macro`: anything invokable as `foo!(...)` in source code. - `MBE`: macro-by-example, a macro defined by `macro_rules`. - `matcher`: the left-hand-side of a rule in a `macro_rules` invocation, or a @@ -84,7 +84,7 @@ r[macro.ambiguity.convention.set] `*`, `+`, and `?`, "OPEN"/"CLOSE" over matching token pairs surrounding a delimited sequence (e.g. `[` and `]`). -r[macro.ambiguity.sequence-vars] +r[macro.ambiguity.convention.sequence-vars] Greek letters "α" "β" "γ" "δ" stand for potentially empty token-tree sequences. (However, the Greek letter "ε" (epsilon) has a special role in the presentation and does not stand for a token-tree sequence.) From 1d77d916aac1515bcb73cb7bc3f3a764bce89d57 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 21 Oct 2024 12:33:49 -0700 Subject: [PATCH 154/189] mdbook-spec: Fix Spec::new visibility In https://github.com/rust-lang/reference/pull/1646 I accidentally changed the visibility of `Spec::new`. It needs to be `pub` in order to work in the upstream integration. --- mdbook-spec/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index e559350..3b1f32e 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -57,7 +57,7 @@ pub struct Spec { } impl Spec { - fn new() -> Result { + pub fn new() -> Result { let deny_warnings = std::env::var("SPEC_DENY_WARNINGS").as_deref() == Ok("1"); let rust_root = std::env::var_os("SPEC_RUST_ROOT").map(PathBuf::from); if deny_warnings && rust_root.is_none() { From 35a887a6c824f4a738df45d7e1c5b4b4d40281c8 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 21 Oct 2024 13:06:39 -0700 Subject: [PATCH 155/189] Add ability to set the rust root directory via the API This adds the ability to set the rust_root via `Spec::new` so that the upstream tool can more easily set this value (since env vars are a little awkward). --- mdbook-spec/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 3b1f32e..27a6d80 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -23,7 +23,7 @@ static ADMONITION_RE: Lazy = Lazy::new(|| { }); pub fn handle_preprocessing() -> Result<(), Error> { - let pre = Spec::new()?; + let pre = Spec::new(None)?; let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?; let book_version = Version::parse(&ctx.mdbook_version)?; @@ -57,9 +57,16 @@ pub struct Spec { } impl Spec { - pub fn new() -> Result { + /// Creates a new `Spec` preprocessor. + /// + /// The `rust_root` parameter specifies an optional path to the root of + /// the rust git checkout. If `None`, it will use the `SPEC_RUST_ROOT` + /// environment variable. If the root is not specified, then no tests will + /// be linked unless `SPEC_DENY_WARNINGS` is set in which case this will + /// return an error.. + pub fn new(rust_root: Option) -> Result { let deny_warnings = std::env::var("SPEC_DENY_WARNINGS").as_deref() == Ok("1"); - let rust_root = std::env::var_os("SPEC_RUST_ROOT").map(PathBuf::from); + let rust_root = rust_root.or_else(|| std::env::var_os("SPEC_RUST_ROOT").map(PathBuf::from)); if deny_warnings && rust_root.is_none() { bail!("SPEC_RUST_ROOT environment variable must be set"); } From 7c445d72267230343b806fe4920049b40d4e3f71 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 22 Oct 2024 06:14:56 -0700 Subject: [PATCH 156/189] Fix example broken by recent rustc change https://github.com/rust-lang/rust/pull/129935 made `unsupported_calling_conventions` a hard-error, which in turn makes this test fail. --- src/items/external-blocks.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index dbd55fb..74a4666 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -66,6 +66,7 @@ standard C ABI on the specific platform. Other ABIs may be specified using an `abi` string, as shown here: ```rust +# #[cfg(any(windows, target_arch = "x86"))] // Interface to the Windows API unsafe extern "stdcall" { } ``` From 506c4a33e756b6826e7cb3f57c677f0e43235ebc Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 22 Oct 2024 06:25:39 -0700 Subject: [PATCH 157/189] Remove `ignore` on windows test This removes the `ignore` on this test since it isn't needed if the test is properly marked for its intended target. --- src/items/external-blocks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 74a4666..21feb0e 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -296,8 +296,8 @@ that symbol rather than having to look it up by name. > [!WARNING] > `link_ordinal` should only be used in cases where the ordinal of the symbol is known to be stable: if the ordinal of a symbol is not explicitly set when its containing binary is built then one will be automatically assigned to it, and that assigned ordinal may change between builds of the binary. - -```rust,ignore +```rust +# #[cfg(all(windows, target_arch = "x86"))] #[link(name = "exporter", kind = "raw-dylib")] unsafe extern "stdcall" { #[link_ordinal(15)] From 4ed8f63695e9ca8b7d5dffbf903b71434d2a40c0 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 22 Oct 2024 07:12:44 -0700 Subject: [PATCH 158/189] Clarify that "macro attributes" refers to proc macros This also allows for the future possibility of `macro_rules`-based attributes. --- src/attributes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes.md b/src/attributes.md index f3ca917..1a316a9 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -44,7 +44,7 @@ The following attributes are unsafe: Attributes can be classified into the following kinds: * [Built-in attributes] -* [Macro attributes][attribute macros] +* [Proc macro attributes][attribute macros] * [Derive macro helper attributes] * [Tool attributes](#tool-attributes) From 4f09bea5e1d050d3ed833fdf348de29700af376b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sat, 19 Oct 2024 20:37:34 +0300 Subject: [PATCH 159/189] Document mixed-site hygiene. --- src/macros-by-example.md | 49 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index dad88a5..78660e0 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -416,11 +416,48 @@ by other crates, either by path or by `#[macro_use]` as described above. r[macro.decl.hygiene] r[macro.decl.hygiene.intro] -By default, all identifiers referred to in a macro are expanded as-is, and are -looked up at the macro's invocation site. This can lead to issues if a macro -refers to an item or macro which isn't in scope at the invocation site. To -alleviate this, the `$crate` metavariable can be used at the start of a path to -force lookup to occur inside the crate defining the macro. + +Macros by example have _mixed-site hygiene_. It means that [loop labels], [block labels] and local variables are looked up at the macro definition site, and other symbols are looked up at the macro invocation site. For example: + +```rust +let x = 1; +fn func() { + unreachable!("this is never called") +} + +macro_rules! check { + () => { + assert_eq!(x, 1); // Uses `x` from the declaration site. + func(); // Uses `func` from the invocation site. + }; +} + +{ + let x = 2; + fn func() { /* does not panic */ } + check!(); +} +``` + +Labels and local variables defined in macro expansion are not shared between invocations, so this code doesn’t compile: + +```rust,compile_fail +macro_rules! m { + (define) => { + let x = 1; + }; + (refer) => { + dbg!(x); + }; +} + +m!(define); +m!(refer); +``` + +r[macro.decl.hygiene.crate] + +A special case is the `$crate` metavariable. It refers to the crate defining the macro, and can be used at the start of the path to look up items or macros which are not in scope at the invocation site. ```rust,ignore @@ -565,6 +602,7 @@ expansions, taking separators into account. This means: For more detail, see the [formal specification]. +[block labels]: expressions/loop-expr.md#labelled-block-expressions [const block]: expressions/block-expr.md#const-blocks [Hygiene]: #hygiene [IDENTIFIER]: identifiers.md @@ -580,6 +618,7 @@ For more detail, see the [formal specification]. [_Expression_]: expressions.md [_Item_]: items.md [_LiteralExpression_]: expressions/literal-expr.md +[loop labels]: expressions/loop-expr.md#loop-labels [_MetaListIdents_]: attributes.md#meta-item-attribute-syntax [_Pattern_]: patterns.md [_PatternNoTopAlt_]: patterns.md From 759bebf309b00348e5aab4f84fc2dc9d21eb5c93 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 22 Oct 2024 20:57:31 +0000 Subject: [PATCH 160/189] Prepare PR #1656 to be merged --- src/macros-by-example.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 78660e0..6d93dab 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -416,8 +416,7 @@ by other crates, either by path or by `#[macro_use]` as described above. r[macro.decl.hygiene] r[macro.decl.hygiene.intro] - -Macros by example have _mixed-site hygiene_. It means that [loop labels], [block labels] and local variables are looked up at the macro definition site, and other symbols are looked up at the macro invocation site. For example: +Macros by example have _mixed-site hygiene_. This means that [loop labels], [block labels], and local variables are looked up at the macro definition site while other symbols are looked up at the macro invocation site. For example: ```rust let x = 1; @@ -427,7 +426,7 @@ fn func() { macro_rules! check { () => { - assert_eq!(x, 1); // Uses `x` from the declaration site. + assert_eq!(x, 1); // Uses `x` from the definition site. func(); // Uses `func` from the invocation site. }; } @@ -441,7 +440,7 @@ macro_rules! check { Labels and local variables defined in macro expansion are not shared between invocations, so this code doesn’t compile: -```rust,compile_fail +```rust,compile_fail,E0425 macro_rules! m { (define) => { let x = 1; @@ -456,7 +455,6 @@ m!(refer); ``` r[macro.decl.hygiene.crate] - A special case is the `$crate` metavariable. It refers to the crate defining the macro, and can be used at the start of the path to look up items or macros which are not in scope at the invocation site. From 4ca4834144b439281380fad34ebfe6bb1f3dc019 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 2 Oct 2024 13:57:50 -0700 Subject: [PATCH 161/189] Fix `pat` fragment specifier to be the "current" edition --- src/macros-by-example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 3c2aef9..aa04467 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -145,7 +145,7 @@ Valid fragment specifiers are: * `lifetime`: a [LIFETIME_TOKEN] * `literal`: matches `-`?[_LiteralExpression_] * `meta`: an [_Attr_], the contents of an attribute - * `pat`: at least any [_PatternNoTopAlt_], and possibly more depending on edition + * `pat`: a [_Pattern_] (see [macro.decl.meta.edition2021]) * `pat_param`: a [_PatternNoTopAlt_] * `path`: a [_TypePath_] style path * `stmt`: a [_Statement_] without the trailing semicolon (except for item statements that require semicolons) From d638f0d4137f27fc39c2198f8903a73d16c7c3ad Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 22 Oct 2024 14:32:29 -0700 Subject: [PATCH 162/189] Merge `--print cfg` with existing note block --- src/conditional-compilation.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index 9775af5..05bd011 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -49,7 +49,7 @@ passed to the compiler outside of the code. It is not possible to set a configuration option from within the source code of the crate being compiled. > **Note**: For `rustc`, arbitrary-set configuration options are set using the -> [`--cfg`] flag. +> [`--cfg`] flag. Configuration values for a specified target can be displayed with `rustc --print cfg --target $TARGET`. > **Note**: Configuration options with the key `feature` are a convention used > by [Cargo][cargo-feature] for specifying compile-time options and optional @@ -58,18 +58,6 @@ configuration option from within the source code of the crate being compiled. > [!WARNING] > Arbitrarily-set configuration options can clash with compiler-set configuration options. For example, it is possible to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and have both `unix` and `windows` configuration options set at the same time. Doing this would be unwise. -Some default configuration values can be obtained from `rustc`: - -```text -rustc --print cfg # optionally, a --target can be specified -target_abi="" -target_arch="aarch64" -target_endian="little" -target_env="" -target_family="unix" -... -``` - ### `target_arch` Key-value option set once with the target's CPU architecture. The value is From 55b20b536274cc13a25e905db35a2326143f8e67 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Mon, 28 Oct 2024 17:25:55 +0100 Subject: [PATCH 163/189] Rename "object safe" to "dyn compatible" --- src/glossary.md | 28 +++++++++++++++++++------ src/items/traits.md | 43 +++++++++++++++++++++++++++------------ src/type-coercions.md | 4 ++-- src/types/trait-object.md | 4 ++-- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/glossary.md b/src/glossary.md index b507476..dabd65d 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -173,12 +173,14 @@ the hierarchy has its own collection of named entities. ### Nominal types Types that can be referred to by a path directly. Specifically [enums], -[structs], [unions], and [trait objects]. +[structs], [unions], and [trait object types]. -### Object safe traits +### Dyn-compatible traits -[Traits] that can be used as [trait objects]. Only traits that follow specific -[rules][object safety] are object safe. +[Traits] that can be used in [trait object types] (`dyn Trait`). +Only traits that follow specific [rules][dyn compatibility] are *dyn compatible*. + +These were formerly known as *object safe* traits. ### Path @@ -293,6 +295,7 @@ example of an uninhabited type is the [never type] `!`, or an enum with no varia [attributes]: attributes.md [*entity*]: names.md [crate]: crates-and-source-files.md +[dyn compatibility]: items/traits.md#dyn-compatibility [enums]: items/enumerations.md [fields]: expressions/field-expr.md [free item]: #free-item @@ -315,12 +318,11 @@ example of an uninhabited type is the [never type] `!`, or an enum with no varia [*name*]: names.md [*namespace*]: names/namespaces.md [never type]: types/never.md -[object safety]: items/traits.md#object-safety [*path*]: paths.md [Paths]: paths.md [*scope*]: names/scopes.md [structs]: items/structs.md -[trait objects]: types/trait-object.md +[trait object types]: types/trait-object.md [traits]: items/traits.md [turbofish test]: https://github.com/rust-lang/rust/blob/1.58.0/src/test/ui/parser/bastion-of-the-turbofish.rs [types of crates]: linkage.md @@ -329,3 +331,17 @@ example of an uninhabited type is the [never type] `!`, or an enum with no varia [unions]: items/unions.md [variable bindings]: patterns.md [visibility rules]: visibility-and-privacy.md + + diff --git a/src/items/traits.md b/src/items/traits.md index cb6c6f9..0f78605 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -52,7 +52,7 @@ Trait functions are not allowed to be [`const`]. Generic items may use traits as [bounds] on their type parameters. -## Generic Traits +## Generic traits Type parameters can be specified for a trait to make it generic. These appear after the trait name, using the same syntax used in [generic functions]. @@ -65,12 +65,12 @@ trait Seq { } ``` -## Object Safety +## Dyn compatibility -Object safe traits can be the base trait of a [trait object]. A trait is -*object safe* if it has the following qualities (defined in [RFC 255]): +A dyn-compatible trait can be the base trait of a [trait object]. A trait is +*dyn compatible* if it has the following qualities: -* All [supertraits] must also be object safe. +* All [supertraits] must also be dyn compatible. * `Sized` must not be a [supertrait][supertraits]. In other words, it must not require `Self: Sized`. * It must not have any associated constants. * It must not have any associated types with generics. @@ -92,11 +92,14 @@ Object safe traits can be the base trait of a [trait object]. A trait is * Explicitly non-dispatchable functions require: * Have a `where Self: Sized` bound (receiver type of `Self` (i.e. `self`) implies this). +This concept was formerly known as *object safety*. +The original set of rules was defined in [RFC 255] and has since been extended. + ```rust # use std::rc::Rc; # use std::sync::Arc; # use std::pin::Pin; -// Examples of object safe methods. +// Examples of dyn compatible methods. trait TraitMethods { fn by_ref(self: &Self) {} fn by_ref_mut(self: &mut Self) {} @@ -113,7 +116,7 @@ trait TraitMethods { ``` ```rust,compile_fail -// This trait is object-safe, but these methods cannot be dispatched on a trait object. +// This trait is dyn compatible, but these methods cannot be dispatched on a trait object. trait NonDispatchable { // Non-methods cannot be dispatched. fn foo() where Self: Sized {} @@ -137,8 +140,8 @@ obj.typed(1); // ERROR: cannot call with generic type ```rust,compile_fail # use std::rc::Rc; -// Examples of non-object safe traits. -trait NotObjectSafe { +// Examples of dyn-incompatible traits. +trait DynIncompatible { const CONST: i32 = 1; // ERROR: cannot have associated const fn foo() {} // ERROR: associated function without Sized @@ -148,14 +151,14 @@ trait NotObjectSafe { } struct S; -impl NotObjectSafe for S { +impl DynIncompatible for S { fn returns(&self) -> Self { S } } -let obj: Box = Box::new(S); // ERROR +let obj: Box = Box::new(S); // ERROR ``` ```rust,compile_fail -// Self: Sized traits are not object-safe. +// `Self: Sized` traits are dyn-incompatible. trait TraitWithSize where Self: Sized {} struct S; @@ -164,7 +167,7 @@ let obj: Box = Box::new(S); // ERROR ``` ```rust,compile_fail -// Not object safe if `Self` is a type argument. +// Dyn-incompatible if `Self` is a type argument. trait Super {} trait WithSelf: Super where Self: Sized {} @@ -349,3 +352,17 @@ fn main() { [`async`]: functions.md#async-functions [`const`]: functions.md#const-functions [type namespace]: ../names/namespaces.md + + diff --git a/src/type-coercions.md b/src/type-coercions.md index a96e749..8215186 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -209,7 +209,7 @@ r[coerce.unsize.slice] * `[T; n]` to `[T]`. r[coerce.unsize.trait-object] -* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [object safe]. +* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [dyn compatible]. r[coerce.unsized.composite] * `Foo<..., T, ...>` to `Foo<..., U, ...>`, when: @@ -322,7 +322,7 @@ precisely. [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md [RFC 1558]: https://github.com/rust-lang/rfcs/blob/master/text/1558-closure-to-fn-coercion.md [subtype]: subtyping.md -[object safe]: items/traits.md#object-safety +[dyn compatible]: items/traits.md#dyn-compatibility [type cast operator]: expressions/operator-expr.md#type-cast-expressions [`Unsize`]: std::marker::Unsize [`CoerceUnsized`]: std::ops::CoerceUnsized diff --git a/src/types/trait-object.md b/src/types/trait-object.md index 598ad29..7a72f33 100644 --- a/src/types/trait-object.md +++ b/src/types/trait-object.md @@ -12,7 +12,7 @@ r[type.trait-object.syntax] r[type.trait-object.intro] A *trait object* is an opaque value of another type that implements a set of -traits. The set of traits is made up of an [object safe] *base trait* plus any +traits. The set of traits is made up of a [dyn compatible] *base trait* plus any number of [auto traits]. r[type.trait-object.impls] @@ -116,6 +116,6 @@ inferred with a sensible choice. [_TypeParamBounds_]: ../trait-bounds.md [auto traits]: ../special-types-and-traits.md#auto-traits [defaults]: ../lifetime-elision.md#default-trait-object-lifetimes +[dyn compatible]: ../items/traits.md#dyn-compatibility [dynamically sized types]: ../dynamically-sized-types.md -[object safe]: ../items/traits.md#object-safety [supertraits]: ../items/traits.md#supertraits From eaf83b99199f21872852b9d5f9f42dac61cf8d7b Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 30 Oct 2024 06:13:13 -0700 Subject: [PATCH 164/189] Fix linkchecker for object-safety This is a temporary workaround since the linkchecker is not aware of javascript fragment redirects. --- src/items/traits.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/items/traits.md b/src/items/traits.md index 0f78605..2b34103 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -65,6 +65,7 @@ trait Seq { } ``` + ## Dyn compatibility A dyn-compatible trait can be the base trait of a [trait object]. A trait is From 0a2d233bed458cd407ab04351ab49d553b0c3316 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 30 Oct 2024 06:16:12 -0700 Subject: [PATCH 165/189] Move historical reference into an editorial note This is not a rule, but an editorial aside. --- src/items/traits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/items/traits.md b/src/items/traits.md index 2b34103..1a83d3b 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -93,8 +93,8 @@ A dyn-compatible trait can be the base trait of a [trait object]. A trait is * Explicitly non-dispatchable functions require: * Have a `where Self: Sized` bound (receiver type of `Self` (i.e. `self`) implies this). -This concept was formerly known as *object safety*. -The original set of rules was defined in [RFC 255] and has since been extended. +> **Note**: This concept was formerly known as *object safety*. +> The original set of rules were defined in [RFC 255] and have since been extended. ```rust # use std::rc::Rc; From c5db4b0076ff71f72f612950e8a8fe32a0dc8a98 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 30 Oct 2024 06:17:44 -0700 Subject: [PATCH 166/189] Remove link to RFC 255 Generally the reference should not be keeping track of the historical evolution of features. --- src/items/traits.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/items/traits.md b/src/items/traits.md index 1a83d3b..bbcd4f9 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -94,7 +94,6 @@ A dyn-compatible trait can be the base trait of a [trait object]. A trait is * Have a `where Self: Sized` bound (receiver type of `Self` (i.e. `self`) implies this). > **Note**: This concept was formerly known as *object safety*. -> The original set of rules were defined in [RFC 255] and have since been extended. ```rust # use std::rc::Rc; @@ -334,7 +333,6 @@ fn main() { [_WhereClause_]: generics.md#where-clauses [bounds]: ../trait-bounds.md [trait object]: ../types/trait-object.md -[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md [associated items]: associated-items.md [method]: associated-items.md#methods [supertraits]: #supertraits From f5a825dc921322c3c9244af530050092c764aff5 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 30 Aug 2024 16:58:55 -0400 Subject: [PATCH 167/189] Add identifier syntax to items.md and subchapters --- src/items.md | 40 +++++++++- src/items/associated-items.md | 87 ++++++++++++++++++---- src/items/constant-items.md | 22 +++++- src/items/enumerations.md | 49 +++++++++++- src/items/extern-crates.md | 19 +++++ src/items/external-blocks.md | 135 ++++++++++++++++++++++++++++++++-- src/items/functions.md | 72 +++++++++++++++++- src/items/generics.md | 33 ++++++++- src/items/implementations.md | 47 +++++++++++- src/items/modules.md | 32 +++++++- src/items/static-items.md | 32 +++++++- src/items/structs.md | 9 +++ src/items/traits.md | 44 +++++++++++ src/items/type-aliases.md | 9 +++ src/items/unions.md | 69 ++++++++++++++--- src/items/use-declarations.md | 65 +++++++++++++++- 16 files changed, 714 insertions(+), 50 deletions(-) diff --git a/src/items.md b/src/items.md index 00639ac..e3763d4 100644 --- a/src/items.md +++ b/src/items.md @@ -1,5 +1,8 @@ # Items +r[items] + +r[items.syntax] > **Syntax:**\ > _Item_:\ >    [_OuterAttribute_]\*\ @@ -28,36 +31,71 @@ >       [_MacroInvocationSemi_]\ >    | [_MacroRulesDefinition_] - +r[items.intro] An _item_ is a component of a crate. Items are organized within a crate by a nested set of [modules]. Every crate has a single "outermost" anonymous module; all further items within the crate have [paths] within the module tree of the crate. +r[items.static-def] Items are entirely determined at compile-time, generally remain fixed during execution, and may reside in read-only memory. +r[items.kinds] There are several kinds of items: +r[items.kind-modules] * [modules] + +r[items.kind-extern-crate] * [`extern crate` declarations] + +r[items.kind-use] * [`use` declarations] + +r[items.kind-fn] * [function definitions] + +r[items.kind-type] * [type definitions] + +r[items.kind-struct] * [struct definitions] + +r[items.kind-enum] * [enumeration definitions] + +r[items.kind-union] * [union definitions] + +r[items.kind-const] * [constant items] + +r[items.kind-static] * [static items] + +r[items.kind-trait] * [trait definitions] + +r[items.kind-impl] * [implementations] + +r[items.kind-extern] * [`extern` blocks] +r[items.locations] Items may be declared in the [root of the crate], a [module][modules], or a [block expression]. + +r[items.associated-locations] A subset of items, called [associated items], may be declared in [traits] and [implementations]. + +r[items.extern-locations] A subset of items, called external items, may be declared in [`extern` blocks]. +r[items.decl-order] Items may be defined in any order, with the exception of [`macro_rules`] which has its own scoping behavior. + +r[items.name-resolution] [Name resolution] of item names allows items to be defined before or after where the item is referred to in the module or block. See [item scopes] for information on the scoping rules of items. diff --git a/src/items/associated-items.md b/src/items/associated-items.md index c4e7a19..d7ba4ea 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -1,5 +1,8 @@ # Associated Items +r[items.associated] + +r[items.associated.syntax] > **Syntax**\ > _AssociatedItem_ :\ >    [_OuterAttribute_]\* (\ @@ -7,39 +10,53 @@ >       | ( [_Visibility_]? ( [_TypeAlias_] | [_ConstantItem_] | [_Function_] ) )\ >    ) +r[items.associated.intro] *Associated Items* are the items declared in [traits] or defined in [implementations]. They are called this because they are defined on an associate -type — the type in the implementation. They are a subset of the kinds of -items you can declare in a module. Specifically, there are [associated -functions] (including methods), [associated types], and [associated constants]. +type — the type in the implementation + +r[items.associated.kinds] +They are a subset of the kinds of items you can declare in a module. +Specifically, there are [associated functions] (including methods), [associated types], and [associated constants]. [associated functions]: #associated-functions-and-methods [associated types]: #associated-types [associated constants]: #associated-constants +r[items.associated.related] Associated items are useful when the associated item logically is related to the associating item. For example, the `is_some` method on `Option` is intrinsically related to Options, so should be associated. +r[items.associated.decl-def] Every associated item kind comes in two varieties: definitions that contain the actual implementation and declarations that declare signatures for definitions. +r[items.associated.trait-items] It is the declarations that make up the contract of traits and what is available on generic types. ## Associated functions and methods +r[items.associated.fn] + +r[items.associated.fn.intro] *Associated functions* are [functions] associated with a type. +r[items.associated.fn.decl] An *associated function declaration* declares a signature for an associated function definition. It is written as a function item, except the function body is replaced with a `;`. -The identifier is the name of the function. The generics, parameter list, -return type, and where clause of the associated function must be the same as the +r[items.associated.name] +The identifier is the name of the function. + +r[items.associated.constraint] +The generics, parameter list, return type, and where clause of the associated function must be the same as the associated function declarations's. +r[items.associated.fn.def] An *associated function definition* defines a function associated with another type. It is written the same as a [function item]. @@ -64,6 +81,7 @@ fn main () { } ``` +r[items.associated.fn.qualified-self] When the associated function is declared on a trait, the function can also be called with a [path] that is a path to the trait appended by the name of the trait. When this happens, it is substituted for `<_ as Trait>::function_name`. @@ -86,10 +104,14 @@ let _: f64 = f64::from_i32(42); ### Methods +r[items.associated.fn.method] + +r[items.associated.fn.method.intro] Associated functions whose first parameter is named `self` are called *methods* and may be invoked using the [method call operator], for example, `x.foo()`, as well as the usual function call notation. +r[items.associated.fn.method.constraint] If the type of the `self` parameter is specified, it is limited to types resolving to one generated by the following grammar (where `'lt` denotes some arbitrary lifetime): @@ -99,6 +121,7 @@ P = &'lt S | &'lt mut S | Box | Rc | Arc | Pin

    S = Self | P ``` +r[items.associated.fn.method.self-ty] The `Self` terminal in this grammar denotes a type resolving to the implementing type. This can also include the contextual type alias `Self`, other type aliases, or associated type projections resolving to the implementing type. @@ -127,6 +150,7 @@ impl Example { } ``` +r[associated.fn.method.self-pat-shorthands] Shorthand syntax can be used without specifying a type, which have the following equivalents: @@ -138,6 +162,7 @@ Shorthand | Equivalent > **Note**: Lifetimes can be, and usually are, elided with this shorthand. +r[associated.fn.method.self-pat-mut] If the `self` parameter is prefixed with `mut`, it becomes a mutable variable, similar to regular parameters using a `mut` [identifier pattern]. For example: @@ -189,21 +214,30 @@ let circle_shape = Circle::new(); let bounding_box = circle_shape.bounding_box(); ``` +r[items.associated.fn.params-edition2015] > **Edition differences**: In the 2015 edition, it is possible to declare trait > methods with anonymous parameters (e.g. `fn foo(u8)`). This is deprecated and > an error as of the 2018 edition. All parameters must have an argument name. #### Attributes on method parameters +r[items.associated.fn.param-attributes] + Attributes on method parameters follow the same rules and restrictions as [regular function parameters]. ## Associated Types -*Associated types* are [type aliases] associated with another type. Associated -types cannot be defined in [inherent implementations] nor can they be given a +r[items.associated.type] + +r[items.associated.type.intro] +*Associated types* are [type aliases] associated with another type. + +r[items.associated.type.constraint] +Associated types cannot be defined in [inherent implementations] nor can they be given a default implementation in traits. +r[items.associated.type.decl] An *associated type declaration* declares a signature for associated type definitions. It is written in one of the following forms, where `Assoc` is the name of the associated type, `Params` is a comma-separated list of type, @@ -221,13 +255,21 @@ type Assoc where WhereBounds; type Assoc: Bounds where WhereBounds; ``` -The identifier is the name of the declared type alias. The optional trait bounds -must be fulfilled by the implementations of the type alias. +r[items.associated.type.name] +The identifier is the name of the declared type alias + +r[items.associated.type.constraint-impl] +The optional trait bounds must be fulfilled by the implementations of the type alias. + +r[items.associated.type.sized] There is an implicit [`Sized`] bound on associated types that can be relaxed using the special `?Sized` bound. +r[items.associated.type.def] An *associated type definition* defines a type alias for the implementation -of a trait on a type. They are written similarly to an *associated type declaration*, -but cannot contain `Bounds`, but instead must contain a `Type`: +of a trait on a type + +r[items.associated.type.restriction-def] +They are written similarly to an *associated type declaration*, but cannot contain `Bounds`, but instead must contain a `Type`: ```rust,ignore @@ -237,11 +279,15 @@ type Assoc = Type where WhereBounds; type Assoc where WhereBounds = Type; // deprecated, prefer the form above ``` +r[items.associated.type.alias] If a type `Item` has an associated type `Assoc` from a trait `Trait`, then `::Assoc` is a type that is an alias of the type specified in the -associated type definition. Furthermore, if `Item` is a type parameter, then -`Item::Assoc` can be used in type parameters. +associated type definition + +r[items.associated.type.param] +Furthermore, if `Item` is a type parameter, then `Item::Assoc` can be used in type parameters. +r[items.associated.type.generic] Associated types may include [generic parameters] and [where clauses]; these are often referred to as *generic associated types*, or *GATs*. If the type `Thing` has an associated type `Item` from a trait `Trait` with the generics `<'a>` , the @@ -300,7 +346,6 @@ fn borrow<'a, T: Lend>(array: &'a mut T) -> ::Lender<'a> { array.lend() } - fn main() { let mut array = [0usize; 16]; let lender = borrow(&mut array); @@ -352,11 +397,15 @@ Given a reference to the associated type like `::Output`, the a ### Required where clauses on generic associated types +r[items.associated.type.generic-where-clause] + +r[items.associated.type.generic-where-clause.intro] Generic associated type declarations on traits currently may require a list of where clauses, dependent on functions in the trait and how the GAT is used. These rules may be loosened in the future; updates can be found [on the generic associated types initiative repository](https://rust-lang.github.io/generic-associated-types-initiative/explainer/required_bounds.html). +r[items.associated.type.generic-where-clause.constraint-valid-fn] In a few words, these where clauses are required in order to maximize the allowed definitions of the associated type in impls. To do this, any clauses that *can be proven to hold* on functions (using the parameters of the function or trait) @@ -373,6 +422,7 @@ In the above, on the `next` function, we can prove that `Self: 'a`, because of the implied bounds from `&'a mut self`; therefore, we must write the equivalent bound on the GAT itself: `where Self: 'x`. +r[items.associated.type.generic-where-clause.constraint-intersection] When there are multiple functions in a trait that use the GAT, then the *intersection* of the bounds from the different functions are used, rather than the union. @@ -390,6 +440,7 @@ know that `T: 'a` on `create_checker`, we do not know that on `do_check`. Howeve if `do_check` was commented out, then the `where T: 'x` bound would be required on `Checker`. +r[items.associated.type.generic-where-clause.constraint-forward] The bounds on associated types also propagate required where clauses. ```rust @@ -404,6 +455,7 @@ Here, `where Self: 'a` is required on `Item` because of `iter`. However, `Item` is used in the bounds of `Iterator`, the `where Self: 'a` clause is also required there. +r[items.associated.type.generic-where-clause.static] Finally, any explicit uses of `'static` on GATs in the trait do not count towards the required bounds. @@ -416,18 +468,25 @@ trait StaticReturn { ## Associated Constants +r[items.associated.const] + +r[items.associated.const.intro] *Associated constants* are [constants] associated with a type. +r[items.associated.const.decl] An *associated constant declaration* declares a signature for associated constant definitions. It is written as `const`, then an identifier, then `:`, then a type, finished by a `;`. +r[items.associated.const.name] The identifier is the name of the constant used in the path. The type is the type that the definition has to implement. +r[items.associated.const.def] An *associated constant definition* defines a constant associated with a type. It is written the same as a [constant item]. +r[items.associated.const.eval] Associated constant definitions undergo [constant evaluation] only when referenced. Further, definitions that include [generic parameters] are evaluated after monomorphization. diff --git a/src/items/constant-items.md b/src/items/constant-items.md index f6ba8da..5333455 100644 --- a/src/items/constant-items.md +++ b/src/items/constant-items.md @@ -1,23 +1,32 @@ # Constant items +r[items.const] + +r[items.const.syntax] > **Syntax**\ > _ConstantItem_ :\ >    `const` ( [IDENTIFIER] | `_` ) `:` [_Type_] ( `=` [_Expression_] )? `;` +r[items.const.intro] A *constant item* is an optionally named _[constant value]_ which is not associated -with a specific memory location in the program. Constants are essentially inlined -wherever they are used, meaning that they are copied directly into the relevant +with a specific memory location in the program. + +r[items.const.behaviour] +Constants are essentially inlined wherever they are used, meaning that they are copied directly into the relevant context when used. This includes usage of constants from external crates, and non-[`Copy`] types. References to the same constant are not necessarily guaranteed to refer to the same memory address. +r[items.const.namespace] The constant declaration defines the constant value in the [value namespace] of the module or block where it is located. +r[items.const.static] Constants must be explicitly typed. The type must have a `'static` lifetime: any references in the initializer must have `'static` lifetimes. References in the type of a constant default to `'static` lifetime; see [static lifetime elision]. +r[items.const.static-temporary] A reference to a constant will have `'static` lifetime if the constant value is eligible for [promotion]; otherwise, a temporary will be created. @@ -39,10 +48,13 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { }; ``` +r[items.const.restriction] The constant expression may only be omitted in a [trait definition]. ## Constants with Destructors +r[items.const.destructor] + Constants can contain destructors. Destructors are run when the value goes out of scope. @@ -66,6 +78,9 @@ fn create_and_drop_zero_with_destructor() { ## Unnamed constant +r[items.const.unnamed] + +r[items.const.unnamed.intro] Unlike an [associated constant], a [free] constant may be unnamed by using an underscore instead of the name. For example: @@ -76,6 +91,7 @@ const _: () = { struct _SameNameTwice; }; const _: () = { struct _SameNameTwice; }; ``` +r[items.const.unnamed.repetition] As with [underscore imports], macros may safely emit the same unnamed constant in the same scope more than once. For example, the following should not produce an error: @@ -92,6 +108,8 @@ m!(const _: () = ();); ## Evaluation +r[items.const.eval] + [Free][free] constants are always [evaluated][const_eval] at compile-time to surface panics. This happens even within an unused function: diff --git a/src/items/enumerations.md b/src/items/enumerations.md index 63a3e76..d2441a1 100644 --- a/src/items/enumerations.md +++ b/src/items/enumerations.md @@ -1,5 +1,8 @@ # Enumerations +r[items.enum] + +r[items.enum.sybtax] > **Syntax**\ > _Enumeration_ :\ >    `enum` @@ -25,11 +28,15 @@ > _EnumItemDiscriminant_ :\ >    `=` [_Expression_] +r[items.enum.intro] An *enumeration*, also referred to as an *enum*, is a simultaneous definition of a nominal [enumerated type] as well as a set of *constructors*, that can be used to create or pattern-match values of the corresponding enumerated type. +r[items.enum.decl] Enumerations are declared with the keyword `enum`. + +r[items.enum.namespace] The `enum` declaration defines the enumeration type in the [type namespace] of the module or block where it is located. An example of an `enum` item and its use: @@ -44,6 +51,7 @@ let mut a: Animal = Animal::Dog; a = Animal::Cat; ``` +r[items.enum.constructor] Enum constructors can have either named or unnamed fields: ```rust @@ -59,6 +67,7 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }; In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is simply called an enum variant. +r[items.enum.fieldless] An enum where no constructors contain fields are called a *field-less enum*. For example, this is a fieldless enum: @@ -70,6 +79,7 @@ enum Fieldless { } ``` +r[items.enum.unit-only] If a field-less enum only contains unit variants, the enum is called an *unit-only enum*. For example: @@ -81,12 +91,20 @@ enum Enum { } ``` +r[items.enum.constructor-names] Variant constructors are similar to [struct] definitions, and can be referenced by a path from the enumeration name, including in [use declarations]. + +r[items.enum.constructor-namespace] Each variant defines its type in the [type namespace], though that type cannot be used as a type specifier. Tuple-like and unit-like variants also define a constructor in the [value namespace]. +r[items.enum.struct-expr] A struct-like variant can be instantiated with a [struct expression]. + +r[items.enum.tuple-expr] A tuple-like variant can be instantiated with a [call expression] or a [struct expression]. + +r[items.enum.path-expr] A unit-like variant can be instantiated with a [path expression] or a [struct expression]. For example: @@ -108,9 +126,13 @@ let z = StructLike { value: 123 }; // Struct expression. ## Discriminants +r[items.enum.discriminant] + +r[items.enum.discrimnant.intro] Each enum instance has a _discriminant_: an integer logically associated to it that is used to determine which variant it holds. +r[items.enum.discriminant.repr-rust] Under the [default representation], the discriminant is interpreted as an `isize` value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout. @@ -119,13 +141,16 @@ another means of distinguishing variants) in its actual memory layout. #### Explicit discriminants +r[items.enum.discriminant.explicit] + +r[items.enum.discriminant.explicit.intro] In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with `=` and a [constant expression]: - +r[items.enum.discriminant.explicit.unit-only] 1. if the enumeration is "[unit-only]". - +r[items.enum.discriminan.explicit.primitive-repr] 2. if a [primitive representation] is used. For example: ```rust @@ -142,6 +167,8 @@ following the variant name with `=` and a [constant expression]: #### Implicit discriminants +r[items.enum.discriminant.implicit] + If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then @@ -160,6 +187,9 @@ assert_eq!(baz_discriminant, 123); #### Restrictions +r[items.enum.discriminant.constraints] + +r[items.enum.discrimnant.constraints.same-discriminant] It is an error when two variants share the same discriminant. ```rust,compile_fail @@ -175,6 +205,7 @@ enum SharedDiscriminantError2 { } ``` +r[items.enum.discrimnant.constraints.above-max-discriminant] It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant. @@ -197,12 +228,17 @@ enum OverflowingDiscriminantError2 { #### Via `mem::discriminant` +r[items.enum.discriminant.access-opaque] + [`std::mem::discriminant`] returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant. #### Casting +r[items.enum.discriminant.coercion] + +r[items.enum.discriminant.coercion.intro] If an enumeration is [unit-only] (with no tuple and struct variants), then its discriminant can be directly accessed with a [numeric cast]; e.g.: @@ -218,6 +254,7 @@ assert_eq!(1, Enum::Bar as isize); assert_eq!(2, Enum::Baz as isize); ``` +r[items.enum.discriminant.coercion.constraint] [Field-less enums] can be casted if they do not have explicit discriminants, or where only unit variants are explicit. ```rust @@ -249,6 +286,8 @@ assert_eq!(22, FieldlessWithDiscrimants::Unit as u8); #### Pointer casting +r[items.enum.discriminant.access-memory] + If the enumeration specifies a [primitive representation], then the discriminant may be reliably accessed via unsafe pointer casting: @@ -277,6 +316,9 @@ assert_eq!(2, struct_like.discriminant()); ## Zero-variant enums +r[items.enum.empty] + +r[items.enum.empty.intro] Enums with zero variants are known as *zero-variant enums*. As they have no valid values, they cannot be instantiated. @@ -284,6 +326,7 @@ no valid values, they cannot be instantiated. enum ZeroVariants {} ``` +r[items.enum.empty.uninhabited] Zero-variant enums are equivalent to the [never type], but they cannot be coerced into other types. @@ -295,6 +338,8 @@ let y: u32 = x; // mismatched type error ## Variant visibility +r[items.enum.constraint-variant-visibility] + Enum variants syntactically allow a [_Visibility_] annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used. diff --git a/src/items/extern-crates.md b/src/items/extern-crates.md index 523e972..b052293 100644 --- a/src/items/extern-crates.md +++ b/src/items/extern-crates.md @@ -1,5 +1,8 @@ # Extern crate declarations +r[items.extern-crate] + +r[items.extern-crate.syntax] > **Syntax:**\ > _ExternCrate_ :\ >    `extern` `crate` _CrateRef_ _AsClause_? `;` @@ -10,11 +13,19 @@ > _AsClause_ :\ >    `as` ( [IDENTIFIER] | `_` ) +r[items.extern-crate.intro] An _`extern crate` declaration_ specifies a dependency on an external crate. + +r[items.extern-crate.namespace] The external crate is then bound into the declaring scope as the given [identifier] in the [type namespace]. + +r[items.extern-crate.extern-prelude] Additionally, if the `extern crate` appears in the crate root, then the crate name is also added to the [extern prelude], making it automatically in scope in all modules. + +r[items.extern-crate.as] The `as` clause can be used to bind the imported crate to a different name. +r[items.exter-crate.lookup] The external crate is resolved to a specific `soname` at compile time, and a runtime linkage requirement to that `soname` is passed to the linker for loading at runtime. The `soname` is resolved at compile time by scanning the @@ -23,6 +34,7 @@ the [`crate_name` attributes] that were declared on the external crate when it w compiled. If no `crate_name` is provided, a default `name` attribute is assumed, equal to the [identifier] given in the `extern crate` declaration. +r[items.extern-crate.self] The `self` crate may be imported which creates a binding to the current crate. In this case the `as` clause must be used to specify the name to bind it to. @@ -37,6 +49,7 @@ extern crate std; // equivalent to: extern crate std as std; extern crate std as ruststd; // linking to 'std' under another name ``` +r[items.extern-crate.name-restrictions] When naming Rust crates, hyphens are disallowed. However, Cargo packages may make use of them. In such case, when `Cargo.toml` doesn't specify a crate name, Cargo will transparently replace `-` with `_` (Refer to [RFC 940] for more @@ -52,16 +65,22 @@ extern crate hello_world; // hyphen replaced with an underscore ## Underscore Imports +r[items.extern-crate.underscore] + +r[items.extern-crate.underscore.intro] An external crate dependency can be declared without binding its name in scope by using an underscore with the form `extern crate foo as _`. This may be useful for crates that only need to be linked, but are never referenced, and will avoid being reported as unused. +r[items.extern-crate.underscore.macro_use] The [`macro_use` attribute] works as usual and imports the macro names into the [`macro_use` prelude]. ## The `no_link` attribute +r[items.extern-crate.no_link] + The *`no_link` attribute* may be specified on an `extern crate` item to prevent linking the crate into the output. This is commonly used to load a crate to access only its macros. diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 21feb0e..6cb49f0 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -1,5 +1,8 @@ # External blocks +r[items.extern] + +r[items.extern.syntax] > **Syntax**\ > _ExternBlock_ :\ >    `unsafe`? `extern` [_Abi_]? `{`\ @@ -13,32 +16,45 @@ >       | ( [_Visibility_]? ( [_StaticItem_] | [_Function_] ) )\ >    ) +r[items.extern.intro] External blocks provide _declarations_ of items that are not _defined_ in the current crate and are the basis of Rust's foreign function interface. These are akin to unchecked imports. +r[items.extern.restriction] Two kinds of item _declarations_ are allowed in external blocks: [functions] and -[statics]. Calling functions or accessing statics that are declared in external -blocks is only allowed in an `unsafe` context. +[statics]. + +r[items.extern.fn-safety] +Calling functions or accessing statics that are declared in external blocks is only allowed in an `unsafe` context. +r[items.extern.namespace] The external block defines its functions and statics in the [value namespace] of the module or block where it is located. ## Functions +r[items.extern.fn] + +r[items.extern.fn.body] Functions within external blocks are declared in the same way as other Rust functions, with the exception that they must not have a body and are instead -terminated by a semicolon. Patterns are not allowed in parameters, only -[IDENTIFIER] or `_` may be used. The `safe` and `unsafe` function qualifiers are +terminated by a semicolon + +r[items.extern.fn.restriction] +Patterns are not allowed in parameters, only [IDENTIFIER] or `_` may be used. The `safe` and `unsafe` function qualifiers are allowed, but other function qualifiers (e.g. `const`, `async`, `extern`) are not. +r[items.extern.fn.foreign-abi] Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler automatically translates between the Rust ABI and the foreign ABI. +r[items.extern.fn.safety] A function declared in an extern block is implicitly `unsafe` unless the `safe` function qualifier is present. +r[items.extern.fn.fn-ptr] When coerced to a function pointer, a function declared in an extern block has type `extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R`, where `'l1`, ... `'lm` are its lifetime parameters, `A1`, ..., `An` are the declared types of @@ -46,14 +62,22 @@ its parameters, `R` is the declared return type. ## Statics +r[items.extern.static] + +r[items.extern.static.intro] Statics within external blocks are declared in the same way as [statics] outside of external blocks, except that they do not have an expression initializing their value. + +r[items.extern.static.safety] Unless a static item declared in an extern block is qualified as `safe`, it is `unsafe` to access that item, whether or not it's mutable, because there is nothing guaranteeing that the bit pattern at the static's memory is valid for the type it is declared with, since some arbitrary (e.g. C) code is in charge of initializing the static. +r[items.extern.static.mut] Extern statics can be either immutable or mutable just like [statics] outside of external blocks. + +r[items.extern.static.read-only] An immutable static *must* be initialized before any Rust code is executed. It is not enough for the static to be initialized before Rust code reads from it. Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, @@ -61,6 +85,9 @@ except if the mutation happens to bytes inside of an `UnsafeCell`. ## ABI +r[items.extern.abi] + +r[items.extern.abi.intro] By default external blocks assume that the library they are calling uses the standard C ABI on the specific platform. Other ABIs may be specified using an `abi` string, as shown here: @@ -71,34 +98,60 @@ standard C ABI on the specific platform. Other ABIs may be specified using an unsafe extern "stdcall" { } ``` +r[items.extern.abi.standard] There are three ABI strings which are cross-platform, and which all compilers are guaranteed to support: +r[items.extern.abi.rust] * `unsafe extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any Rust code. + +r[items.extern.abi.c] * `unsafe extern "C"` -- This is the same as `extern fn foo()`; whatever the default your C compiler supports. + +r[items.extern.abi.system] * `unsafe extern "system"` -- Usually the same as `extern "C"`, except on Win32, in which case it's `"stdcall"`, or what you should use to link to the Windows API itself +r[items.extern.abi.platform] There are also some platform-specific ABI strings: +r[items.extern.abi.cdecl] * `unsafe extern "cdecl"` -- The default for x86\_32 C code. + +r[items.extern.abi.stdcall] * `unsafe extern "stdcall"` -- The default for the Win32 API on x86\_32. + +r[items.extern.abi.win64] * `unsafe extern "win64"` -- The default for C code on x86\_64 Windows. + +r[items.extern.abi.sysv64] * `unsafe extern "sysv64"` -- The default for C code on non-Windows x86\_64. + +r[items.extern.abi.aapcs] * `unsafe extern "aapcs"` -- The default for ARM. + +r[items.extern.abi.fastcall] * `unsafe extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's `__fastcall` and GCC and clang's `__attribute__((fastcall))` + +r[items.extern.abi.vectorcall] * `unsafe extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's `__vectorcall` and clang's `__attribute__((vectorcall))` + +r[items.extern.abi.thiscall] * `unsafe extern "thiscall"` -- The default for C++ member functions on MSVC -- corresponds to MSVC's `__thiscall` and GCC and clang's `__attribute__((thiscall))` + +r[items.extern.abi.efiapi] * `unsafe extern "efiapi"` -- The ABI used for [UEFI] functions. ## Variadic functions +r[items.extern.variadic] + Functions within external blocks may be variadic by specifying `...` as the last argument. The variadic parameter may optionally be specified with an identifier. @@ -113,36 +166,58 @@ unsafe extern "C" { ## Attributes on extern blocks +r[items.extern.attributes] + +r[items.extern.attributes.intro] The following [attributes] control the behavior of external blocks. ### The `link` attribute +r[items.extern.attributes.link] + +r[items.extern.attributes.link.intro] The *`link` attribute* specifies the name of a native library that the -compiler should link with for the items within an `extern` block. It uses the -[_MetaListNameValueStr_] syntax to specify its inputs. The `name` key is the +compiler should link with for the items within an `extern` block. + +r[items.extern.attributes.link.syntax] +It uses the [_MetaListNameValueStr_] syntax to specify its inputs. The `name` key is the name of the native library to link. The `kind` key is an optional value which specifies the kind of library with the following possible values: +r[items.extern.attributes.link.dylib] - `dylib` --- Indicates a dynamic library. This is the default if `kind` is not specified. + +r[items.extern.attributes.link.static] - `static` --- Indicates a static library. + +r[items.extern.attributes.link.framework] - `framework` --- Indicates a macOS framework. This is only valid for macOS targets. + +r[items.extern.attributes.link.raw-dylib] - `raw-dylib` --- Indicates a dynamic library where the compiler will generate an import library to link against (see [`dylib` versus `raw-dylib`] below for details). This is only valid for Windows targets. +r[items.extern.attributes.link.constraint] The `name` key must be included if `kind` is specified. +r[items.extern.attributes.link.modifiers] The optional `modifiers` argument is a way to specify linking modifiers for the library to link. + +r[items.extern.attributes.link.modifiers-syntax] Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. + +r[items.extern.attributes.link.modifiers-constraint] Specifying multiple `modifiers` arguments in a single `link` attribute, or multiple identical modifiers in the same `modifiers` argument is not currently supported. \ Example: `#[link(name = "mylib", kind = "static", modifiers = "+whole-archive")]`. +r[items.extern.attributes.link.wasm_import_module] The `wasm_import_module` key may be used to specify the [WebAssembly module] name for the items within an `extern` block when importing symbols from the host environment. The default module name is `env` if `wasm_import_module` is @@ -166,6 +241,7 @@ unsafe extern { } ``` +r[items.extern.attributes.link.empty-block] It is valid to add the `link` attribute on an empty extern block. You can use this to satisfy the linking requirements of extern blocks elsewhere in your code (including upstream crates) instead of adding the attribute to each extern @@ -173,13 +249,18 @@ block. #### Linking modifiers: `bundle` +r[items.extern.attributes.link.modifier-bundle] + +r[items.extern.attributes.link.modifier-bundle.constraint] This modifier is only compatible with the `static` linking kind. Using any other kind will result in a compiler error. +r[items.extern.attributes.link.modifier-bundle.behaviour] When building a rlib or staticlib `+bundle` means that the native static library will be packed into the rlib or staticlib archive, and then retrieved from there during linking of the final binary. +r[items.extern.attributes.link.modifier-bundle.behaviour-negative] When building a rlib `-bundle` means that the native static library is registered as a dependency of that rlib "by name", and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking. \ @@ -187,8 +268,10 @@ When building a staticlib `-bundle` means that the native static library is simp into the archive and some higher level build system will need to add it later during linking of the final binary. +r[items.extern.attributes.link.modifier-bundle.no-effect] This modifier has no effect when building other targets like executables or dynamic libraries. +r[items.extern.attributes.link.modifier-bundle.default] The default for this modifier is `+bundle`. More implementation details about this modifier can be found in @@ -196,12 +279,17 @@ More implementation details about this modifier can be found in #### Linking modifiers: `whole-archive` +r[items.extern.attributes.link.modifier-whole-archive] + +r[items.extern.attributes.link.modifier-whole-archive.constraint] This modifier is only compatible with the `static` linking kind. Using any other kind will result in a compiler error. +r[items.extern.attributes.link.modifier-whole-archive.behaviour] `+whole-archive` means that the static library is linked as a whole archive without throwing any object files away. +r[items.extern.attributes.link.modifier-whole-archive.default] The default for this modifier is `-whole-archive`. More implementation details about this modifier can be found in @@ -209,15 +297,21 @@ More implementation details about this modifier can be found in ### Linking modifiers: `verbatim` +r[items.extern.attributes.link.modifier-verbatim] + +r[items.extern.attributes.link.modifier-verbatim.constraint] This modifier is compatible with all linking kinds. +r[items.extern.attributes.link.modifier-verbatim.behaviour] `+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker. +r[items.extern.attributes.link.modifier-verbatim.behaviour-negative] `-verbatim` means that rustc will either add a target-specific prefix and suffix to the library name before passing it to linker, or won't prevent linker from implicitly adding it. +r[items.extern.attributes.link.modifier-verbatim.default] The default for this modifier is `-verbatim`. More implementation details about this modifier can be found in @@ -225,22 +319,30 @@ More implementation details about this modifier can be found in #### `dylib` versus `raw-dylib` +r[items.extern.attributes.link.kind-raw-dylib] + +r[items.extern.attributes.link.kind-raw-dylib.intro] On Windows, linking against a dynamic library requires that an import library is provided to the linker: this is a special static library that declares all of the symbols exported by the dynamic library in such a way that the linker knows that they have to be dynamically loaded at runtime. +r[items.extern.attributes.link.kind-raw-dylib.import] Specifying `kind = "dylib"` instructs the Rust compiler to link an import library based on the `name` key. The linker will then use its normal library resolution logic to find that import library. Alternatively, specifying `kind = "raw-dylib"` instructs the compiler to generate an import library during compilation and provide that to the linker instead. +r[items.extern.attributes.link.kind-raw-dylib.platform-specific] `raw-dylib` is only supported on Windows. Using it when targeting other platforms will result in a compiler error. #### The `import_name_type` key +r[items.extern.attributes.link.import_name_type] + +r[items.extern.attributes.link.import_name_type.intro] On x86 Windows, names of functions are "decorated" (i.e., have a specific prefix and/or suffix added) to indicate their calling convention. For example, a `stdcall` calling convention function with the name `fn1` that has no arguments @@ -250,6 +352,7 @@ use different decorations for the same calling conventions which means, by default, some Win32 functions cannot be called using the `raw-dylib` link kind via the GNU toolchain. +r[items.extern.attributes.link.import_name_type.values] To allow for these differences, when using the `raw-dylib` link kind you may also specify the `import_name_type` key with one of the following values to change how functions are named in the generated import library: @@ -260,20 +363,28 @@ change how functions are named in the generated import library: format, but skipping the leading `?`, `@`, or optionally `_`. * `undecorated`: The function name will not be decorated. +r[items.extern.attributes.link.import_name_type.default] If the `import_name_type` key is not specified, then the function name will be fully-decorated using the target toolchain's format. +r[items.extern.attributes.link.import_name_type.variables] Variables are never decorated and so the `import_name_type` key has no effect on how they are named in the generated import library. +r[items.extern.attributes.link.import_name_type.platform-specific] The `import_name_type` key is only supported on x86 Windows. Using it when targeting other platforms will result in a compiler error. ### The `link_name` attribute +r[items.extern.attributes.link_name] + +r[items.extern.attributes.link_name.intro] The *`link_name` attribute* may be specified on declarations inside an `extern` -block to indicate the symbol to import for the given function or static. It -uses the [_MetaNameValueStr_] syntax to specify the name of the symbol. +block to indicate the symbol to import for the given function or static. + +r[items.extern.attributes.link_name.syntax] +It uses the [_MetaNameValueStr_] syntax to specify the name of the symbol. ```rust unsafe extern { @@ -282,11 +393,15 @@ unsafe extern { } ``` +r[items.extern.attributes.link_name.exclusive] Using this attribute with the `link_ordinal` attribute will result in a compiler error. ### The `link_ordinal` attribute +r[items.extern.attributes.link_ordinal] + +r[items.extern.attributes.link_ordinal.intro] The *`link_ordinal` attribute* can be applied on declarations inside an `extern` block to indicate the numeric ordinal to use when generating the import library to link against. An ordinal is a unique number per symbol exported by a dynamic @@ -305,14 +420,18 @@ unsafe extern "stdcall" { } ``` +r[items.extern.attributes.link_ordinal.constraints] This attribute is only used with the `raw-dylib` linking kind. Using any other kind will result in a compiler error. +r[items.extern.attributes.link_ordinal.exclusive] Using this attribute with the `link_name` attribute will result in a compiler error. ### Attributes on function parameters +r[items.extern.attributes.fn-parameters] + Attributes on extern function parameters follow the same rules and restrictions as [regular function parameters]. diff --git a/src/items/functions.md b/src/items/functions.md index d3f2c45..4235269 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -1,5 +1,8 @@ # Functions +r[items.fn] + +r[items.fn.syntax] > **Syntax**\ > _Function_ :\ >    _FunctionQualifiers_ `fn` [IDENTIFIER] [_GenericParams_]?\ @@ -48,13 +51,21 @@ > [^fn-param-2015]: Function parameters with only a type are only allowed > in an associated function of a [trait item] in the 2015 edition. +r[items.fn.intro] A _function_ consists of a [block] (that's the _body_ of the function), along with a name, a set of parameters, and an output type. Other than a name, all these are optional. + +r[items.fn.namespace] Functions are declared with the keyword `fn` which defines the given name in the [value namespace] of the module or block where it is located. + +r[items.fn.signature] Functions may declare a set of *input* [*variables*][variables] as parameters, through which the caller passes arguments into the function, and the *output* [*type*][type] of the value the function will return to its caller on completion. + +r[items.fn.implicit-return] If the output type is not explicitly stated, it is the [unit type]. +r[items.fn.fn-item-type] When referred to, a _function_ yields a first-class *value* of the corresponding zero-sized [*function item type*], which when called evaluates to a direct call to the function. For example, this is a simple function: @@ -64,10 +75,14 @@ fn answer_to_life_the_universe_and_everything() -> i32 { } ``` +r[items.fn.constraint-safety-qualifiers] The `safe` function is semantically only allowed when used in an [`extern` block]. ## Function parameters +r[items.fn.params] + +r[items.fn.params.intro] Function parameters are irrefutable [patterns], so any pattern that is valid in an else-less `let` binding is also valid as a parameter: @@ -75,16 +90,24 @@ an else-less `let` binding is also valid as a parameter: fn first((value, _): (i32, i32)) -> i32 { value } ``` +r[items.fn.params.self-pat] If the first parameter is a _SelfParam_, this indicates that the function is a -[method]. Functions with a self parameter may only appear as an [associated +[method]. + +r[items.fn.params.self-constraint] +Functions with a self parameter may only appear as an [associated function] in a [trait] or [implementation]. +r[items.fn.params.varargs] A parameter with the `...` token indicates a [variadic function], and may only be used as the last parameter of an [external block] function. The variadic parameter may have an optional identifier, such as `args: ...`. ## Function body +r[items.fn.body] + +r[items.fn.body.intro] The body block of a function is conceptually wrapped in another block that first binds the argument patterns and then `return`s the value of the function's body. This means that the tail expression of the block, if evaluated, ends up being @@ -102,11 +125,15 @@ return { }; ``` +r[items.fn.body.restriction] Functions without a body block are terminated with a semicolon. This form may only appear in a [trait] or [external block]. ## Generic functions +r[items.fn.generics] + +r[items.fn.generics.intro] A _generic function_ allows one or more _parameterized types_ to appear in its signature. Each type parameter must be explicitly declared in an angle-bracket-enclosed and comma-separated list, following the function name. @@ -118,8 +145,12 @@ fn foo(x: A, y: B) { # } ``` +r[items.fn.generics.param-names] Inside the function signature and body, the name of the type parameter can be -used as a type name. [Trait] bounds can be specified for type +used as a type name. + +r[items.fn.generics.param-bounds] +[Trait] bounds can be specified for type parameters to allow methods with that trait to be called on values of that type. This is specified using the `where` syntax: @@ -129,6 +160,7 @@ fn foo(x: T) where T: Debug { # } ``` +r[items.fn.generics.mono] When a generic function is referenced, its type is instantiated based on the context of the reference. For example, calling the `foo` function here: @@ -144,6 +176,7 @@ foo(&[1, 2]); will instantiate type parameter `T` with `i32`. +r[items.fn.generics.explicit-arguments] The type parameters can also be explicitly supplied in a trailing [path] component after the function name. This might be necessary if there is not sufficient context to determine the type parameters. For example, @@ -151,6 +184,9 @@ sufficient context to determine the type parameters. For example, ## Extern function qualifier +r[items.fn.extern] + +r[items.fn.extern.intro] The `extern` function qualifier allows providing function _definitions_ that can be called with a particular ABI: @@ -159,6 +195,7 @@ be called with a particular ABI: extern "ABI" fn foo() { /* ... */ } ``` +r[items.fn.extern.def] These are often used in combination with [external block] items which provide function _declarations_ that can be used to call functions without providing their _definition_: @@ -173,6 +210,7 @@ unsafe { foo() }; bar(); ``` +r[items.fn.extern.default-abi] When `"extern" Abi?*` is omitted from `FunctionQualifiers` in function items, the ABI `"Rust"` is assigned. For example: @@ -186,6 +224,7 @@ is equivalent to: extern "Rust" fn foo() {} ``` +r[items.fn.extern.foreign-call] Functions can be called by foreign code, and using an ABI that differs from Rust allows, for example, to provide functions that can be called from other programming languages like C: @@ -199,6 +238,7 @@ extern "C" fn new_i32() -> i32 { 0 } extern "stdcall" fn new_i32_stdcall() -> i32 { 0 } ``` +r[items.fn.extern.default-extern] Just as with [external block], when the `extern` keyword is used and the `"ABI"` is omitted, the ABI used defaults to `"C"`. That is, this: @@ -214,6 +254,7 @@ extern "C" fn new_i32() -> i32 { 0 } let fptr: extern "C" fn() -> i32 = new_i32; ``` +r[items.fn.extern.unwind] Functions with an ABI that differs from `"Rust"` do not support unwinding in the exact same way that Rust does. Therefore, unwinding past the end of functions with such ABIs causes the process to abort. @@ -223,16 +264,24 @@ aborts the process by executing an illegal instruction. ## Const functions +r[items.fn.const] + +r[item.fn.const.intro] Functions qualified with the `const` keyword are [const functions], as are [tuple struct] and [tuple variant] constructors. _Const functions_ can be called from within [const contexts]. +r[item.fn.const.extern] Const functions may use the [`extern`] function qualifier. +r[items.fn.const.exclusivity] Const functions are not allowed to be [async](#async-functions). ## Async functions +r[items.fn.async] + +r[items.fn.async.intro] Functions may be qualified as async, and this can also be combined with the `unsafe` qualifier: @@ -241,10 +290,12 @@ async fn regular_example() { } async unsafe fn unsafe_example() { } ``` +r[items.fn.async.future] Async functions do no work when called: instead, they capture their arguments into a future. When polled, that future will execute the function's body. +r[items.fn.async.desugar-brief] An async function is roughly equivalent to a function that returns [`impl Future`] and with an [`async move` block][async-blocks] as its body: @@ -266,12 +317,16 @@ fn example<'a>(x: &'a str) -> impl Future + 'a { } ``` +r[items.fn.async.desugar] The actual desugaring is more complex: +r[items.fn.async.lifetime-catpure] - The return type in the desugaring is assumed to capture all lifetime parameters from the `async fn` declaration. This can be seen in the desugared example above, which explicitly outlives, and hence captures, `'a`. + +r[items.fn.async.param-capture] - The [`async move` block][async-blocks] in the body captures all function parameters, including those that are unused or bound to a `_` pattern. This ensures that function parameters are dropped in the @@ -284,11 +339,15 @@ For more information on the effect of async, see [`async` blocks][async-blocks]. [async-blocks]: ../expressions/block-expr.md#async-blocks [`impl Future`]: ../types/impl-trait.md +r[items.fn.async.edition2018] > **Edition differences**: Async functions are only available beginning with > Rust 2018. ### Combining `async` and `unsafe` +r[items.fn.async.safety] + +r[items.fn.async.safety.intro] It is legal to declare a function that is both async and unsafe. The resulting function is unsafe to call and (like any async function) returns a future. This future is just an ordinary future and thus an @@ -314,6 +373,7 @@ async fn safe_example() { } ``` +r[items.fn.async.safety.] Note that this behavior is a consequence of the desugaring to a function that returns an `impl Future` -- in this case, the function we desugar to is an `unsafe` function, but the return value remains @@ -331,6 +391,9 @@ responsibility to ensure that. ## Attributes on functions +r[items.fn.attributes] + +r[items.fn.attributes.intro] [Outer attributes][attributes] are allowed on functions. [Inner attributes][attributes] are allowed directly after the `{` inside its body [block]. @@ -346,6 +409,7 @@ fn documented() { > Note: Except for lints, it is idiomatic to only use outer attributes on > function items. +r[items.fn.attributes.builtin-attributes] The attributes that have meaning on a function are [`cfg`], [`cfg_attr`], [`deprecated`], [`doc`], [`export_name`], [`link_section`], [`no_mangle`], [the lint check attributes], [`must_use`], [the procedural macro attributes], [the testing @@ -354,6 +418,9 @@ attributes macros. ## Attributes on function parameters +r[items.fn.param-attributes] + +r[items.fn.param-attributes.intro] [Outer attributes][attributes] are allowed on function parameters and the permitted [built-in attributes] are restricted to `cfg`, `cfg_attr`, `allow`, `warn`, `deny`, and `forbid`. @@ -367,6 +434,7 @@ fn len( } ``` +r[items.fn.param-attributes.parsed-attributes] Inert helper attributes used by procedural macro attributes applied to items are also allowed but be careful to not include these inert attributes in your final `TokenStream`. diff --git a/src/items/generics.md b/src/items/generics.md index 9b75659..498de74 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -1,5 +1,8 @@ # Generic parameters +r[items.generics] + +r[items.generics.syntax] > **Syntax**\ > _GenericParams_ :\ >       `<` `>`\ @@ -17,12 +20,17 @@ > _ConstParam_:\ >    `const` [IDENTIFIER] `:` [_Type_] ( `=` _[Block][block]_ | [IDENTIFIER] | -?[LITERAL] )? +r[items.generics.syntax.intro] [Functions], [type aliases], [structs], [enumerations], [unions], [traits], and [implementations] may be *parameterized* by types, constants, and lifetimes. These parameters are listed in angle brackets (`<...>`), usually immediately after the name of the item and before its definition. For implementations, which don't have a name, they come directly after `impl`. + +r[items.generics.syntax.decl-order] The order of generic parameters is restricted to lifetime parameters and then type and const parameters intermixed. + +r[items.generics.syntax.constraint] The same parameter name may not be declared more than once in a _GenericParams_ list. Some examples of items with type, const, and lifetime parameters: @@ -35,25 +43,35 @@ struct InnerArray([T; N]); struct EitherOrderWorks(U); ``` +r[items.generics.syntax.scope] Generic parameters are in scope within the item definition where they are declared. They are not in scope for items declared within the body of a function as described in [item declarations]. See [generic parameter scopes] for more details. +r[items.generics.builtin-generic-types] [References], [raw pointers], [arrays], [slices], [tuples], and [function pointers] have lifetime or type parameters as well, but are not referred to with path syntax. +r[items.generics.constraint-widlcard-lifetime] `'_` is not a valid lifetime parameter. ### Const generics +r[items.generics.const] + +r[items.generics.const.intro] *Const generic parameters* allow items to be generic over constant values. + +r[items.generics.const.namespace] The const identifier introduces a name in the [value namespace] for the constant parameter, and all instances of the item must be instantiated with a value of the given type. +r[items.generics.const.constraint] The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`. +r[items.generics.const.usage] Const parameters can be used anywhere a [const item] can be used, with the exception that when used in a [type] or [array repeat expression], it must be standalone (as described below). That is, they are allowed in the following @@ -111,6 +129,7 @@ fn foo() { } ``` +r[items.generics.const.constraint-const-expr] As a further restriction, const parameters may only appear as a standalone argument inside of a [type] or [array repeat expression]. In those contexts, they may only be used as a single segment [path expression], possibly inside a @@ -128,7 +147,10 @@ fn bad_function() -> [u8; {N + 1}] { } ``` +r[items.generics.const.argument] A const argument in a [path] specifies the const value to use for that item. + +r[items.generics.const.argument-restriction] The argument must be a [const expression] of the type ascribed to the const parameter. The const expression must be a [block expression][block] (surrounded with braces) unless it is a single path segment (an [IDENTIFIER]) @@ -154,6 +176,7 @@ fn example() { } ``` +r[items.generics.const.type-ambiguity] When there is ambiguity if a generic argument could be resolved as either a type or const argument, it is always resolved as a type. Placing the argument in a block expression can force it to be interpreted as a const argument. @@ -172,6 +195,7 @@ fn foo() -> Foo { todo!() } // ERROR fn bar() -> Foo<{ N }> { todo!() } // ok ``` +r[items.generics.const.variance] Unlike type and lifetime parameters, const parameters can be declared without being used inside of a parameterized item, with the exception of implementations as described in [generic implementations]: @@ -188,6 +212,7 @@ struct Unconstrained; impl Unconstrained {} ``` +r[items.generics.const.exhaustiveness] When resolving a trait bound obligation, the exhaustiveness of all implementations of const parameters is not considered when determining if the bound is satisfied. For example, in the following, even though all possible @@ -207,9 +232,11 @@ fn generic() { } ``` - ## Where clauses +r[items.generics.where] + +r[items.generics.where.syntax] > **Syntax**\ > _WhereClause_ :\ >    `where` ( _WhereClauseItem_ `,` )\* _WhereClauseItem_ ? @@ -224,10 +251,12 @@ fn generic() { > _TypeBoundWhereClauseItem_ :\ >    [_ForLifetimes_]? [_Type_] `:` [_TypeParamBounds_]? +r[items.generics.where.intro] *Where clauses* provide another way to specify bounds on type and lifetime parameters as well as a way to specify bounds on types that aren't type parameters. +r[items.generics.where.higher-ranked-;ifetimes] The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only allows [_LifetimeParam_] parameters. @@ -245,6 +274,8 @@ where ## Attributes +r[items.generics.attributes] + Generic lifetime and type parameters allow [attributes] on them. There are no built-in attributes that do anything in this position, although custom derive attributes may give meaning to it. diff --git a/src/items/implementations.md b/src/items/implementations.md index 3796556..6f631f3 100644 --- a/src/items/implementations.md +++ b/src/items/implementations.md @@ -1,5 +1,8 @@ # Implementations +r[items.impl] + +r[items.impl.syntax] > **Syntax**\ > _Implementation_ :\ >    _InherentImpl_ | _TraitImpl_ @@ -19,11 +22,13 @@ >       [_AssociatedItem_]\*\ >    `}` +r[items.impl.intro] An _implementation_ is an item that associates items with an _implementing type_. Implementations are defined with the keyword `impl` and contain functions that belong to an instance of the type that is being implemented or to the type statically. +r[items.impl.kinds] There are two types of implementations: - inherent implementations @@ -31,22 +36,33 @@ There are two types of implementations: ## Inherent Implementations +r[items.impl.inherent] + +r[items.impl.inherent.intro] An inherent implementation is defined as the sequence of the `impl` keyword, generic type declarations, a path to a nominal type, a where clause, and a bracketed set of associable items. +r[items.impl.inherent.implementing-type] The nominal type is called the _implementing type_ and the associable items are the _associated items_ to the implementing type. +r[items.impl.inherent.associated-items] Inherent implementations associate the contained items to the -implementing type. Inherent implementations can contain [associated -functions] (including [methods]) and [associated constants]. They cannot -contain associated type aliases. +implementing type. + +r[items.impl.inherent.values] +Inherent implementations can contain [associated functions] (including [methods]) and [associated constants]. +r[items.impl.inherent.constraint-type-alias] +They cannot contain associated type aliases. + +r[items.impl.inherent.associated-item-path] The [path] to an associated item is any path to the implementing type, followed by the associated item's identifier as the final path component. +r[items.impl.inherent.coherence] A type can also have multiple inherent implementations. An implementing type must be defined within the same crate as the original type definition. @@ -86,23 +102,30 @@ fn main() { ## Trait Implementations +r[items.impl.trait] + +r[items.impl.trait.intro] A _trait implementation_ is defined like an inherent implementation except that the optional generic type declarations are followed by a [trait], followed by the keyword `for`, followed by a path to a nominal type. +r[items.impl.trait.implemented-trait] The trait is known as the _implemented trait_. The implementing type implements the implemented trait. +r[items.impl.trait.constraint] A trait implementation must define all non-default associated items declared by the implemented trait, may redefine default associated items defined by the implemented trait, and cannot define any other items. +r[items.impl.trait.associated-item-path] The path to the associated items is `<` followed by a path to the implementing type followed by `as` followed by a path to the trait followed by `>` as a path component followed by the associated item's path component. +r[items.impl.trait.safety] [Unsafe traits] require the trait implementation to begin with the `unsafe` keyword. @@ -140,9 +163,13 @@ impl Shape for Circle { ### Trait Implementation Coherence +r[items.impl.trait.coherence] + +r[items.impl.trait.coherence.intro] A trait implementation is considered incoherent if either the orphan rules check fails or there are overlapping implementation instances. +r[items.impl.trait.coherence.overlapping] Two trait implementations overlap when there is a non-empty intersection of the traits the implementation is for, the implementations can be instantiated with the same type. #### Orphan rules +r[items.impl.trait.orphan-rule] + +r[items.impl.trait.orphan-rule.general] Given `impl Trait for T0`, an `impl` is valid only if at least one of the following is true: @@ -160,14 +190,19 @@ least one of the following is true: - No [uncovered type] parameters `P1..=Pn` may appear in `T0..Ti` (excluding `Ti`) +r[items.impl.trait.uncovered-param] Only the appearance of *uncovered* type parameters is restricted. + +r[items.impl.trait.fundamental] Note that for the purposes of coherence, [fundamental types] are special. The `T` in `Box` is not considered covered, and `Box` is considered local. - ## Generic Implementations +r[items.impl.generics] + +r[items.impl.generics.intro] An implementation can take [generic parameters], which can be used in the rest of the implementation. Implementation parameters are written directly after the `impl` keyword. @@ -182,6 +217,7 @@ impl Seq for u32 { } ``` +r[items.impl.generics.usage] Generic parameters *constrain* an implementation if the parameter appears at least once in one of: @@ -190,6 +226,7 @@ least once in one of: * As an [associated type] in the [bounds] of a type that contains another parameter that constrains the implementation +r[items.impl.generics.constraint] Type and const parameters must always constrain the implementation. Lifetimes must constrain the implementation if the lifetime is used in an associated type. @@ -263,6 +300,8 @@ impl<'a> HasAssocType for Struct { ## Attributes on Implementations +r[items.impl.attributes] + Implementations may contain outer [attributes] before the `impl` keyword and inner [attributes] inside the brackets that contain the associated items. Inner attributes must come before any associated items. The attributes that have diff --git a/src/items/modules.md b/src/items/modules.md index e709f52..8617e15 100644 --- a/src/items/modules.md +++ b/src/items/modules.md @@ -1,5 +1,8 @@ # Modules +r[items.mod] + +r[items.mod.syntax] > **Syntax:**\ > _Module_ :\ >       `unsafe`? `mod` [IDENTIFIER] `;`\ @@ -8,11 +11,16 @@ >         [_Item_]\*\ >       `}` +r[items.mod.intro] A module is a container for zero or more [items]. +r[items.mod.def] A _module item_ is a module, surrounded in braces, named, and prefixed with the keyword `mod`. A module item introduces a new, named module into the tree of -modules making up a crate. Modules can nest arbitrarily. +modules making up a crate. + +r[items.mod.nesting] +Modules can nest arbitrarily. An example of a module: @@ -34,10 +42,14 @@ mod math { } ``` +r[items.mod.namespace] Modules are defined in the [type namespace] of the module or block where they are located. + +r[items.mod.namespace-def] It is an error to define multiple items with the same name in the same namespace within a module. See the [scopes chapter] for more details on restrictions and shadowing behavior. +r[items.mod.constraint] The `unsafe` keyword is syntactically allowed to appear before the `mod` keyword, but it is rejected at a semantic level. This allows macros to consume the syntax and make use of the `unsafe` keyword, before removing it from the @@ -45,9 +57,15 @@ token stream. ## Module Source Filenames +r[items.mod.outlined] + +r[items.mod.outlined.intro] A module without a body is loaded from an external file. When the module does not have a `path` attribute, the path to the file mirrors the logical [module -path]. Ancestor module path components are directories, and the module's +path]. + +r[items.mod.outlined.search] +Ancestor module path components are directories, and the module's contents are in a file with the name of the module plus the `.rs` extension. For example, the following module structure can have this corresponding filesystem structure: @@ -58,6 +76,7 @@ Module Path | Filesystem Path | File Contents `crate::util` | `util.rs` | `mod config;` `crate::util::config` | `util/config.rs` | +r[items.mod.outlined.search-mod] Module filenames may also be the name of the module as a directory with the contents in a file named `mod.rs` within that directory. The above example can alternately be expressed with `crate::util`'s contents in a file named @@ -70,9 +89,13 @@ alternately be expressed with `crate::util`'s contents in a file named ### The `path` attribute +r[items.mod.outlined.path] + +r[items.mod.outlined.path.intro] The directories and files used for loading external file modules can be influenced with the `path` attribute. +r[items.mod.outlined.path.search] For `path` attributes on modules not inside inline module blocks, the file path is relative to the directory the source file is located. For example, the following code snippet would use the paths shown based on where it is located: @@ -88,6 +111,7 @@ Source File | `c`'s File Location | `c`'s Module Path `src/a/b.rs` | `src/a/foo.rs` | `crate::a::b::c` `src/a/mod.rs` | `src/a/foo.rs` | `crate::a::c` +r[items.mod.outlined.path.search-nested] For `path` attributes inside inline module blocks, the relative location of the file path depends on the kind of source file the `path` attribute is located in. "mod-rs" source files are root modules (such as `lib.rs` or @@ -128,10 +152,14 @@ mod thread { ## Attributes on Modules +r[items.mod.attributes] + +r[items.mod.attributes.intro] Modules, like all items, accept outer attributes. They also accept inner attributes: either after `{` for a module with a body, or at the beginning of the source file, after the optional BOM and shebang. +r[items.mod.attributes.supported] The built-in attributes that have meaning on a module are [`cfg`], [`deprecated`], [`doc`], [the lint check attributes], [`path`], and [`no_implicit_prelude`]. Modules also accept macro attributes. diff --git a/src/items/static-items.md b/src/items/static-items.md index f688a90..5589071 100644 --- a/src/items/static-items.md +++ b/src/items/static-items.md @@ -1,5 +1,8 @@ # Static items +r[items.static] + +r[items.static.syntax] > **Syntax**\ > _StaticItem_ :\ >    [_ItemSafety_]?[^extern-safety] `static` `mut`? [IDENTIFIER] `:` [_Type_] @@ -8,33 +11,48 @@ > [^extern-safety]: The `safe` and `unsafe` function qualifiers are only > allowed semantically within `extern` blocks. +r[items.static.intro] A *static item* is similar to a [constant], except that it represents a precise memory location in the program. All references to the static refer to the same -memory location. Static items have the `static` lifetime, which outlives all +memory location. + +r[items.static.lifetime] +Static items have the `static` lifetime, which outlives all other lifetimes in a Rust program. Static items do not call [`drop`] at the end of the program. +r[items.static.namespace] The static declaration defines a static value in the [value namespace] of the module or block where it is located. +r[items.static.init] The static initializer is a [constant expression] evaluated at compile time. Static initializers may refer to other statics. +r[items.static.read-only] Non-`mut` static items that contain a type that is not [interior mutable] may be placed in read-only memory. +r[items.static.safety] All access to a static is safe, but there are a number of restrictions on statics: +r[items.static.constraint-sync] * The type must have the `Sync` trait bound to allow thread-safe access. + +r[items.static.constraint-const] * Constants cannot refer to statics. +r[items.static.restriction-init] The initializer expression must be omitted in an [external block], and must be provided for free static items. +r[items.static.constraint-safety-qualifier] The `safe` and `unsafe` qualifiers are semantically only allowed when used in an [external block]. ## Statics & generics +r[items.static.generics] + A static item defined in a generic scope (for example in a blanket or default implementation) will result in exactly one static item being defined, as if the static definition was pulled out of the current scope into the module. @@ -83,14 +101,21 @@ blanket_impl: counter was 1 ## Mutable statics +r[items.static.mut] + +r[items.static.mut.intro] If a static item is declared with the `mut` keyword, then it is allowed to be modified by the program. One of Rust's goals is to make concurrency bugs hard to run into, and this is obviously a very large source of race conditions or -other bugs. For this reason, an `unsafe` block is required when either reading +other bugs + +r[items.static.mut.safety] +For this reason, an `unsafe` block is required when either reading or writing a mutable static variable. Care should be taken to ensure that modifications to a mutable static are safe with respect to other threads running in the same process. +r[items.static.mut.extern] Mutable statics are still very useful, however. They can be used with C libraries and can also be bound from C libraries in an `extern` block. @@ -122,11 +147,14 @@ fn bump_levels_safe() -> u32 { } ``` +r[items.static.mut.constraints] Mutable statics have the same restrictions as normal statics, except that the type does not have to implement the `Sync` trait. ## Using Statics or Consts +r[items.static.alternate] + It can be confusing whether or not you should use a constant item or a static item. Constants should, in general, be preferred over statics unless one of the following are true: diff --git a/src/items/structs.md b/src/items/structs.md index e59d7e9..8a6c9eb 100644 --- a/src/items/structs.md +++ b/src/items/structs.md @@ -1,5 +1,8 @@ # Structs +r[items.struct] + +r[items.struct.syntax] > **Syntax**\ > _Struct_ :\ >       _StructStruct_\ @@ -36,7 +39,10 @@ >    [_Visibility_]?\ >    [_Type_] +r[items.struct.intro] A _struct_ is a nominal [struct type] defined with the keyword `struct`. + +r[items.struct.namespace] A struct declaration defines the given name in the [type namespace] of the module or block where it is located. An example of a `struct` item and its use: @@ -47,6 +53,7 @@ let p = Point {x: 10, y: 11}; let px: i32 = p.x; ``` +r[items.struct.tuple] A _tuple struct_ is a nominal [tuple type], and is also defined with the keyword `struct`. In addition to defining a type, it also defines a constructor of the same name in the [value namespace]. The constructor is a function which can be called to create a new instance of the struct. @@ -58,6 +65,7 @@ let p = Point(10, 11); let px: i32 = match p { Point(x, _) => x }; ``` +r[items.struct.unit] A _unit-like struct_ is a struct without any fields, defined by leaving off the list of fields entirely. Such a struct implicitly defines a [constant] of its type with the same name. For example: @@ -75,6 +83,7 @@ const Cookie: Cookie = Cookie {}; let c = [Cookie, Cookie {}, Cookie, Cookie {}]; ``` +r[items.struct.layout] The precise memory layout of a struct is not specified. One can specify a particular layout using the [`repr` attribute]. diff --git a/src/items/traits.md b/src/items/traits.md index bbcd4f9..baafe9c 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -1,5 +1,8 @@ # Traits +r[items.trait] + +r[items.trait.syntax] > **Syntax**\ > _Trait_ :\ >    `unsafe`? `trait` [IDENTIFIER]  @@ -10,6 +13,7 @@ >      [_AssociatedItem_]\*\ >    `}` +r[items.trait.intro] A _trait_ describes an abstract interface that types can implement. This interface consists of [associated items], which come in three varieties: @@ -17,16 +21,22 @@ interface consists of [associated items], which come in three varieties: - [types](associated-items.md#associated-types) - [constants](associated-items.md#associated-constants) +r[items.trait.namespace] The trait declaration defines a trait in the [type namespace] of the module or block where it is located. + +r[items.trait.associated-item-namespaces] Associated items are defined as members of the trait within their respective namespaces. Associated types are defined in the type namespace. Associated constants and associated functions are defined in the value namespace. +r[items.trait.self-param] All traits define an implicit type parameter `Self` that refers to "the type that is implementing this interface". Traits may also contain additional type parameters. These type parameters, including `Self`, may be constrained by other traits and so forth [as usual][generics]. +r[items.trait.impls] Traits are implemented for specific types through separate [implementations]. +r[item.trait.associated-item-decls] Trait functions may omit the function body by replacing it with a semicolon. This indicates that the implementation must define the function. If the trait function defines a body, this definition acts as a default for any @@ -46,14 +56,19 @@ trait Example { } ``` +r[items.trait.fn-constraint] Trait functions are not allowed to be [`const`]. ## Trait bounds +r[items.traits.bounds] + Generic items may use traits as [bounds] on their type parameters. ## Generic traits +r[items.traits.generic] + Type parameters can be specified for a trait to make it generic. These appear after the trait name, using the same syntax used in [generic functions]. @@ -68,13 +83,25 @@ trait Seq { ## Dyn compatibility +r[items.trait.dyn-compatible] + +r[items.trait.dyn-compatible.intro] A dyn-compatible trait can be the base trait of a [trait object]. A trait is *dyn compatible* if it has the following qualities: +r[items.trait.dyn-compatible.supertraits] * All [supertraits] must also be dyn compatible. + +r[items.trait.dyn-compatible.sized] * `Sized` must not be a [supertrait][supertraits]. In other words, it must not require `Self: Sized`. + +r[items.trait.dyn-compatible.associated-consts] * It must not have any associated constants. + +r[items.trait.dyn-compatible.associated-types] * It must not have any associated types with generics. + +r[items.trait.dyn-compatible.associated-functions] * All associated functions must either be dispatchable from a trait object or be explicitly non-dispatchable: * Dispatchable functions must: * Not have any type parameters (although lifetime parameters are allowed). @@ -179,14 +206,19 @@ let obj: Box = Box::new(S); // ERROR: cannot use `Self` type param ## Supertraits +r[items.trait.supertraits] + +r[items.trait.supertraits.intro] **Supertraits** are traits that are required to be implemented for a type to implement a specific trait. Furthermore, anywhere a [generic][generics] or [trait object] is bounded by a trait, it has access to the associated items of its supertraits. +r[items.trait.supertraits.decl] Supertraits are declared by trait bounds on the `Self` type of a trait and transitively the supertraits of the traits declared in those trait bounds. It is an error for a trait to be its own supertrait. +r[items.trait.supertraits.subtrait] The trait with a supertrait is called a **subtrait** of its supertrait. The following is an example of declaring `Shape` to be a supertrait of `Circle`. @@ -245,6 +277,9 @@ let nonsense = circle.radius() * circle.area(); ## Unsafe traits +r[items.trait.safety] + +r[items.trait.safety.intro] Traits items that begin with the `unsafe` keyword indicate that *implementing* the trait may be [unsafe]. It is safe to use a correctly implemented unsafe trait. The [trait implementation] must also begin with the `unsafe` keyword. @@ -253,11 +288,15 @@ The [trait implementation] must also begin with the `unsafe` keyword. ## Parameter patterns +r[items.trait.params] + +r[items.trait.params.constraint] Function or method declarations without a body only allow [IDENTIFIER] or `_` [wild card][WildcardPattern] patterns. `mut` [IDENTIFIER] is currently allowed, but it is deprecated and will become a hard error in the future. +r[items.trait.params.edition2015] In the 2015 edition, the pattern for a trait function or method parameter is optional: @@ -268,6 +307,7 @@ trait T { } ``` +r[items.trait.params.restriction] The kinds of patterns for parameters is limited to one of the following: * [IDENTIFIER] @@ -276,6 +316,7 @@ The kinds of patterns for parameters is limited to one of the following: * `&` [IDENTIFIER] * `&&` [IDENTIFIER] +r[items.trait.params.restriction-edition2018] Beginning in the 2018 edition, function or method parameter patterns are no longer optional. Also, all irrefutable patterns are allowed as long as there is a body. Without a body, the limitations listed above are still in effect. @@ -289,6 +330,9 @@ trait T { ## Item visibility +r[items.trait.associated-visibility] + +r[items.trait.associated-visibility.intro] Trait items syntactically allow a [_Visibility_] annotation, but this is rejected when the trait is validated. This allows items to be parsed with a unified syntax across different contexts where they are used. As an example, diff --git a/src/items/type-aliases.md b/src/items/type-aliases.md index ef3e6fc..4346395 100644 --- a/src/items/type-aliases.md +++ b/src/items/type-aliases.md @@ -1,11 +1,15 @@ # Type aliases +r[items.type] + +r[items.type.syntax] > **Syntax**\ > _TypeAlias_ :\ >    `type` [IDENTIFIER] [_GenericParams_]? > ( `:` [_TypeParamBounds_] )? > [_WhereClause_]? ( `=` [_Type_] [_WhereClause_]?)? `;` +r[items.type.intro] A _type alias_ defines a new name for an existing [type] in the [type namespace] of the module or block where it is located. Type aliases are declared with the keyword `type`. Every value has a single, specific type, but may implement several different traits, and may be compatible with several different type constraints. @@ -18,6 +22,7 @@ type Point = (u8, u8); let p: Point = (41, 68); ``` +r[items.type.constraint-constructor] A type alias to a tuple-struct or unit-struct cannot be used to qualify that type's constructor: ```rust,compile_fail @@ -30,15 +35,19 @@ let _ = UseAlias(5); // OK let _ = TypeAlias(5); // Doesn't work ``` +r[items.type.constraint] A type alias, when not used as an [associated type], must include a [_Type_] and may not include [_TypeParamBounds_]. +r[items.type.constraint-associated-trait] A type alias, when used as an [associated type] in a [trait], must not include a [_Type_] specification but may include [_TypeParamBounds_]. +r[items.type.constraint-associated-impl] A type alias, when used as an [associated type] in a [trait impl], must include a [_Type_] specification and may not include [_TypeParamBounds_]. +r[items.type.deprecated] Where clauses before the equals sign on a type alias in a [trait impl] (like `type TypeAlias where T: Foo = Bar`) are deprecated. Where clauses after the equals sign (like `type TypeAlias = Bar where T: Foo`) are preferred. diff --git a/src/items/unions.md b/src/items/unions.md index d6a03ed..f1e696a 100644 --- a/src/items/unions.md +++ b/src/items/unions.md @@ -1,12 +1,18 @@ # Unions +r[items.union] + +r[items.union.syntax] > **Syntax**\ > _Union_ :\ >    `union` [IDENTIFIER] [_GenericParams_]? [_WhereClause_]? > `{`[_StructFields_]? `}` +r[items.union.intro] A union declaration uses the same syntax as a struct declaration, except with `union` in place of `struct`. + +r[items.union.namespace] A union declaration defines the given name in the [type namespace] of the module or block where it is located. ```rust @@ -17,24 +23,39 @@ union MyUnion { } ``` +r[items.union.common-storage] The key property of unions is that all fields of a union share common storage. As a result, writes to one field of a union can overwrite its other fields, and size of a union is determined by the size of its largest field. +r[items.union.field-constraints] Union field types are restricted to the following subset of types: + +r[items.union.field-copy] - `Copy` types + +r[items.union.field-references] - References (`&T` and `&mut T` for arbitrary `T`) + +r[items.union.field-manually-drop] - `ManuallyDrop` (for arbitrary `T`) + +r[items.union.field-tuple] - Tuples and arrays containing only allowed union field types +r[items.union.drop] This restriction ensures, in particular, that union fields never need to be dropped. Like for structs and enums, it is possible to `impl Drop` for a union to manually define what happens when it gets dropped. +r[items.union.constraint] Unions without any fields are not accepted by the compiler, but can be accepted by macros. ## Initialization of a union +r[items.union.init] + +r[items.union.init.intro] A value of a union type can be created using the same syntax that is used for struct types, except that it must specify exactly one field: @@ -44,6 +65,7 @@ struct types, except that it must specify exactly one field: let u = MyUnion { f1: 1 }; ``` +r[items.union.init.result] The expression above creates a value of type `MyUnion` and initializes the storage using field `f1`. The union can be accessed using the same syntax as struct fields: @@ -57,18 +79,28 @@ let f = unsafe { u.f1 }; ## Reading and writing union fields +r[items.union.fields] + +r[items.union.fields.intro] Unions have no notion of an "active field". Instead, every union access just -interprets the storage as the type of the field used for the access. Reading a -union field reads the bits of the union at the field's type. Fields might have a -non-zero offset (except when [the C representation] is used); in that case the -bits starting at the offset of the fields are read. It is the programmer's -responsibility to make sure that the data is valid at the field's type. Failing +interprets the storage as the type of the field used for the access. + +r[items.union.fields.read] +Reading a union field reads the bits of the union at the field's type. + +r[items.union.fields.offset] +Fields might have a non-zero offset (except when [the C representation] is used); in that case the +bits starting at the offset of the fields are read + +r[items.union.fields.precondition] +It is the programmer's responsibility to make sure that the data is valid at the field's type. Failing to do so results in [undefined behavior]. For example, reading the value `3` from a field of the [boolean type] is undefined behavior. Effectively, writing to and then reading from a union with [the C representation] is analogous to a [`transmute`] from the type used for writing to the type used for reading. +r[items.union.fields.read-safety] Consequently, all reads of union fields have to be placed in `unsafe` blocks: ```rust @@ -83,6 +115,7 @@ unsafe { Commonly, code using unions will provide safe wrappers around unsafe union field accesses. +r[items.union.fields.write-safety] In contrast, writes to union fields are safe, since they just overwrite arbitrary data, but cannot cause undefined behavior. (Note that union field types can never have drop glue, so a union field write will never implicitly @@ -90,10 +123,17 @@ drop anything.) ## Pattern matching on unions -Another way to access union fields is to use pattern matching. Pattern matching -on union fields uses the same syntax as struct patterns, except that the pattern -must specify exactly one field. Since pattern matching is like reading the union -with a particular field, it has to be placed in `unsafe` blocks as well. +r[items.union.pattern] + +r[items.union.pattern.intro] +Another way to access union fields is to use pattern matching. + +r[items.union.pattern.constraint] +Pattern matching on union fields uses the same syntax as struct patterns, except that the pattern +must specify exactly one field. + +r[items.union.pattern.safety] +Since pattern matching is like reading the union with a particular field, it has to be placed in `unsafe` blocks as well. ```rust # union MyUnion { f1: u32, f2: f32 } @@ -108,6 +148,7 @@ fn f(u: MyUnion) { } ``` +r[items.union.pattern.subpattern] Pattern matching may match a union as a field of a larger structure. In particular, when using a Rust union to implement a C tagged union via FFI, this allows matching on the tag and the corresponding field simultaneously: @@ -141,9 +182,14 @@ fn is_zero(v: Value) -> bool { ## References to union fields +r[items.union.ref] + +r[items.union.ref.intro] Since union fields share common storage, gaining write access to one field of a -union can give write access to all its remaining fields. Borrow checking rules -have to be adjusted to account for this fact. As a result, if one field of a +union can give write access to all its remaining fields. + +r[items.union.ref.borrow] +Borrow checking rules have to be adjusted to account for this fact. As a result, if one field of a union is borrowed, all its remaining fields are borrowed as well for the same lifetime. @@ -164,6 +210,7 @@ fn test() { } ``` +r[items.union.ref.usage] As you could see, in many aspects (except for layouts, safety, and ownership) unions behave exactly like structs, largely as a consequence of inheriting their syntactic shape from structs. This is also true for many unmentioned diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index 4e10960..1b6a228 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -1,5 +1,8 @@ # Use declarations +r[items.use] + +r[items.use.syntax] > **Syntax:**\ > _UseDeclaration_ :\ >    `use` _UseTree_ `;` @@ -9,6 +12,7 @@ >    | ([_SimplePath_]? `::`)? `{` (_UseTree_ ( `,` _UseTree_ )\* `,`?)? `}`\ >    | [_SimplePath_] ( `as` ( [IDENTIFIER] | `_` ) )? +r[items.use.intro] A _use declaration_ creates one or more local name bindings synonymous with some other [path]. Usually a `use` declaration is used to shorten the path required to refer to a module item. These declarations may appear in [modules] @@ -19,17 +23,27 @@ A `use` declaration is also sometimes called an _import_, or, if it is public, a [modules]: modules.md [blocks]: ../expressions/block-expr.md +r[items.use.modes] Use declarations support a number of convenient shortcuts: +r[items.use.mode-multiple] * Simultaneously binding a list of paths with a common prefix, using the brace syntax `use a::b::{c, d, e::f, g::h::i};` + +r[items.use.mode-self] * Simultaneously binding a list of paths with a common prefix and their common parent module, using the `self` keyword, such as `use a::b::{self, c, d::e};` + +r[items.use.mode-as] * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`. This can also be used with the last two features: `use a::b::{self as ab, c as abc}`. + +r[items.use.mode-glob] * Binding all paths matching a given prefix, using the asterisk wildcard syntax `use a::b::*;`. + +r[items.use.mode-nesting] * Nesting groups of the previous features multiple times, such as `use a::b::{self as ab, c, d::{*, e::f}};` @@ -58,12 +72,18 @@ fn main() { ## `use` Visibility +r[items.use.vis] + +r[items.use.visibility.intro] Like items, `use` declarations are private to the containing module, by default. Also like items, a `use` declaration can be public, if qualified by the `pub` keyword. Such a `use` declaration serves to _re-export_ a name. A public `use` declaration can therefore _redirect_ some public name to a different target definition: even a definition with a private canonical path, -inside a different module. If a sequence of such redirections form a cycle or +inside a different module. + +r[items.use.visibility.constraint] +If a sequence of such redirections form a cycle or cannot be resolved unambiguously, they represent a compile-time error. An example of re-exporting: @@ -88,6 +108,9 @@ In this example, the module `quux` re-exports two public names defined in ## `use` Paths +r[items.use.path] + +r[items.use.path.intro] The [paths] that are allowed in a `use` item follow the [_SimplePath_] grammar and are similar to the paths that may be used in an expression. They may create bindings for: @@ -97,8 +120,10 @@ They may create bindings for: * [Attributes] * [Derive macros] +r[items.use.path.constraint] They cannot import [associated items], [generic parameters], [local variables], paths with [`Self`], or [tool attributes]. More restrictions are described below. +r[items.use.path.namespace] `use` will create bindings for all [namespaces] from the imported entities, with the exception that a `self` import will only import from the type namespace (as described below). For example, the following illustrates creating bindings for the same name in two namespaces: @@ -116,6 +141,7 @@ fn example() { } ``` +r[items.use.path.edition2015] > **Edition differences**: In the 2015 edition, `use` paths are relative to the crate root. > For example: > @@ -141,6 +167,8 @@ fn example() { ## `as` renames +r[item.use.as] + The `as` keyword can be used to change the name of an imported entity. For example: @@ -155,6 +183,9 @@ mod inner { ## Brace syntax +r[item.use.multiple-syntax] + +r[item.use.multiple-syntax.intro] Braces can be used in the last segment of the path to import multiple entities from the previous segment, or, if there are no previous segments, from the current scope. Braces can be nested, creating a tree of paths, where each grouping of segments is logically combined with its parent to create a full path. @@ -166,13 +197,18 @@ Braces can be nested, creating a tree of paths, where each grouping of segments use std::collections::{BTreeSet, hash_map::{self, HashMap}}; ``` +r[item.use.multiple-syntax.sempty] An empty brace does not import anything, though the leading path is validated that it is accessible. +r[item.use.multiple-syntax.edition2015] > **Edition differences**: In the 2015 edition, paths are relative to the crate root, so an import such as `use {foo, bar};` will import the names `foo` and `bar` from the crate root, whereas starting in 2018, those names are relative to the current scope. ## `self` imports +r[item.use.self] + +r[item.use.self.intro] The keyword `self` may be used within [brace syntax](#brace-syntax) to create a binding of the parent entity under its own name. ```rust @@ -191,6 +227,7 @@ mod example { # fn main() {} ``` +r[item.use.self.namespace] `self` only creates a binding from the [type namespace] of the parent entity. For example, in the following, only the `foo` mod is imported: @@ -215,6 +252,9 @@ fn main() { ## Glob imports +r[item.use.glob] + +r[item.use.glob.intro] The `*` character may be used as the last segment of a `use` path to import all importable entities from the entity of the preceding segment. For example: @@ -237,6 +277,7 @@ mod foo { } ``` +r[item.use.glob.shadowing] Items and named imports are allowed to shadow names from glob imports in the same [namespace]. That is, if there is a name already defined by another item in the same namespace, the glob import will be shadowed. For example: @@ -268,20 +309,26 @@ mod clashing { } ``` +r[item.use.glob.restriction] `*` cannot be used as the first or intermediate segments. `*` cannot be used to import a module's contents into itself (such as `use self::*;`). +r[item.use.glob.edition2015] > **Edition differences**: In the 2015 edition, paths are relative to the crate root, so an import such as `use *;` is valid, and it means to import everything from the crate root. > This cannot be used in the crate root itself. ## Underscore Imports +r[item.use.as-underscore] + +r[item.use.as-underscore.intro] Items can be imported without binding to a name by using an underscore with the form `use path as _`. This is particularly useful to import a trait so that its methods may be used without importing the trait's symbol, for example if the trait's symbol may conflict with another symbol. Another example is to link an external crate without importing its name. +r[item.use.as-underscore.glob] Asterisk glob imports will import items imported with `_` in their unnameable form. @@ -303,6 +350,7 @@ fn main() { } ``` +r[item.use.as-underscore.macro] The unique, unnameable symbols are created after macro expansion so that macros may safely emit multiple references to `_` imports. For example, the following should not produce an error: @@ -320,12 +368,23 @@ m!(use std as _;); ## Restrictions +r[item.use.restriction] + The following are restrictions for valid `use` declarations: +r[item.use.restriction.crate] * `use crate;` must use `as` to define the name to which to bind the crate root. + +r[item.use.restriction.self] * `use {self};` is an error; there must be a leading segment when using `self`. + +r[item.use.restriction.duplicate-name] * As with any item definition, `use` imports cannot create duplicate bindings of the same name in the same namespace in a module or block. + +r[item.use.restriction.macro-crate] * `use` paths with `$crate` are not allowed in a [`macro_rules`] expansion. + +r[item.use.restriction.variant] * `use` paths cannot refer to enum variants through a [type alias]. For example: ```rust,compile_fail enum MyEnum { @@ -339,10 +398,14 @@ The following are restrictions for valid `use` declarations: ## Ambiguities +r[item.use.ambiguity] + > **Note**: This section is incomplete. +r[item.use.ambiguity.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[item.use.ambiguity.glob] Glob imports are allowed to import conflicting names in the same namespace as long as the name is not used. For example: From 0850e67599c23d6d8e3807ad0e075f6daedf6130 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 12 Sep 2024 10:32:20 -0400 Subject: [PATCH 168/189] Remove trailing spaces --- src/items/modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/modules.md b/src/items/modules.md index 8617e15..3244aad 100644 --- a/src/items/modules.md +++ b/src/items/modules.md @@ -17,7 +17,7 @@ A module is a container for zero or more [items]. r[items.mod.def] A _module item_ is a module, surrounded in braces, named, and prefixed with the keyword `mod`. A module item introduces a new, named module into the tree of -modules making up a crate. +modules making up a crate\1 r[items.mod.nesting] Modules can nest arbitrarily. From ce0ac44fd220595ed655ba2e0f9f3f55a83f48d7 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 30 Oct 2024 10:39:56 -0700 Subject: [PATCH 169/189] Consistently use "items" --- src/items/functions.md | 2 +- src/items/traits.md | 2 +- src/items/use-declarations.md | 52 +++++++++++++++++------------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/items/functions.md b/src/items/functions.md index 4235269..3b258d1 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -266,7 +266,7 @@ aborts the process by executing an illegal instruction. r[items.fn.const] -r[item.fn.const.intro] +r[items.fn.const.intro] Functions qualified with the `const` keyword are [const functions], as are [tuple struct] and [tuple variant] constructors. _Const functions_ can be called from within [const contexts]. diff --git a/src/items/traits.md b/src/items/traits.md index baafe9c..a16ad01 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -36,7 +36,7 @@ other traits and so forth [as usual][generics]. r[items.trait.impls] Traits are implemented for specific types through separate [implementations]. -r[item.trait.associated-item-decls] +r[items.trait.associated-item-decls] Trait functions may omit the function body by replacing it with a semicolon. This indicates that the implementation must define the function. If the trait function defines a body, this definition acts as a default for any diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index 1b6a228..c66f073 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -167,7 +167,7 @@ r[items.use.path.edition2015] ## `as` renames -r[item.use.as] +r[items.use.as] The `as` keyword can be used to change the name of an imported entity. For example: @@ -183,9 +183,9 @@ mod inner { ## Brace syntax -r[item.use.multiple-syntax] +r[items.use.multiple-syntax] -r[item.use.multiple-syntax.intro] +r[items.use.multiple-syntax.intro] Braces can be used in the last segment of the path to import multiple entities from the previous segment, or, if there are no previous segments, from the current scope. Braces can be nested, creating a tree of paths, where each grouping of segments is logically combined with its parent to create a full path. @@ -197,18 +197,18 @@ Braces can be nested, creating a tree of paths, where each grouping of segments use std::collections::{BTreeSet, hash_map::{self, HashMap}}; ``` -r[item.use.multiple-syntax.sempty] +r[items.use.multiple-syntax.sempty] An empty brace does not import anything, though the leading path is validated that it is accessible. -r[item.use.multiple-syntax.edition2015] +r[items.use.multiple-syntax.edition2015] > **Edition differences**: In the 2015 edition, paths are relative to the crate root, so an import such as `use {foo, bar};` will import the names `foo` and `bar` from the crate root, whereas starting in 2018, those names are relative to the current scope. ## `self` imports -r[item.use.self] +r[items.use.self] -r[item.use.self.intro] +r[items.use.self.intro] The keyword `self` may be used within [brace syntax](#brace-syntax) to create a binding of the parent entity under its own name. ```rust @@ -227,7 +227,7 @@ mod example { # fn main() {} ``` -r[item.use.self.namespace] +r[items.use.self.namespace] `self` only creates a binding from the [type namespace] of the parent entity. For example, in the following, only the `foo` mod is imported: @@ -252,9 +252,9 @@ fn main() { ## Glob imports -r[item.use.glob] +r[items.use.glob] -r[item.use.glob.intro] +r[items.use.glob.intro] The `*` character may be used as the last segment of a `use` path to import all importable entities from the entity of the preceding segment. For example: @@ -277,7 +277,7 @@ mod foo { } ``` -r[item.use.glob.shadowing] +r[items.use.glob.shadowing] Items and named imports are allowed to shadow names from glob imports in the same [namespace]. That is, if there is a name already defined by another item in the same namespace, the glob import will be shadowed. For example: @@ -309,26 +309,26 @@ mod clashing { } ``` -r[item.use.glob.restriction] +r[items.use.glob.restriction] `*` cannot be used as the first or intermediate segments. `*` cannot be used to import a module's contents into itself (such as `use self::*;`). -r[item.use.glob.edition2015] +r[items.use.glob.edition2015] > **Edition differences**: In the 2015 edition, paths are relative to the crate root, so an import such as `use *;` is valid, and it means to import everything from the crate root. > This cannot be used in the crate root itself. ## Underscore Imports -r[item.use.as-underscore] +r[items.use.as-underscore] -r[item.use.as-underscore.intro] +r[items.use.as-underscore.intro] Items can be imported without binding to a name by using an underscore with the form `use path as _`. This is particularly useful to import a trait so that its methods may be used without importing the trait's symbol, for example if the trait's symbol may conflict with another symbol. Another example is to link an external crate without importing its name. -r[item.use.as-underscore.glob] +r[items.use.as-underscore.glob] Asterisk glob imports will import items imported with `_` in their unnameable form. @@ -350,7 +350,7 @@ fn main() { } ``` -r[item.use.as-underscore.macro] +r[items.use.as-underscore.macro] The unique, unnameable symbols are created after macro expansion so that macros may safely emit multiple references to `_` imports. For example, the following should not produce an error: @@ -368,23 +368,23 @@ m!(use std as _;); ## Restrictions -r[item.use.restriction] +r[items.use.restriction] The following are restrictions for valid `use` declarations: -r[item.use.restriction.crate] +r[items.use.restriction.crate] * `use crate;` must use `as` to define the name to which to bind the crate root. -r[item.use.restriction.self] +r[items.use.restriction.self] * `use {self};` is an error; there must be a leading segment when using `self`. -r[item.use.restriction.duplicate-name] +r[items.use.restriction.duplicate-name] * As with any item definition, `use` imports cannot create duplicate bindings of the same name in the same namespace in a module or block. -r[item.use.restriction.macro-crate] +r[items.use.restriction.macro-crate] * `use` paths with `$crate` are not allowed in a [`macro_rules`] expansion. -r[item.use.restriction.variant] +r[items.use.restriction.variant] * `use` paths cannot refer to enum variants through a [type alias]. For example: ```rust,compile_fail enum MyEnum { @@ -398,14 +398,14 @@ r[item.use.restriction.variant] ## Ambiguities -r[item.use.ambiguity] +r[items.use.ambiguity] > **Note**: This section is incomplete. -r[item.use.ambiguity.intro] +r[items.use.ambiguity.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[item.use.ambiguity.glob] +r[items.use.ambiguity.glob] Glob imports are allowed to import conflicting names in the same namespace as long as the name is not used. For example: From 67eb9199e726e7689e6009f8b965e76255b3fcb4 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 31 Oct 2024 14:13:46 -0700 Subject: [PATCH 170/189] Rule annotation cleanup A few things for cleanup: - Fix spelling and formatting - Remove rules in a list. The list is more of an index, the items aren't intended to be rules themselves. - Use some more consistent naming. - Use plurals where appropriate. - Avoid generic "constraint" terminology. --- src/items.md | 25 --------------- src/items/associated-items.md | 23 +++++++------- src/items/constant-items.md | 4 +-- src/items/enumerations.md | 16 +++++----- src/items/extern-crates.md | 2 +- src/items/external-blocks.md | 49 +++++++++++++++-------------- src/items/functions.md | 11 +++---- src/items/generics.md | 12 ++++---- src/items/implementations.md | 8 ++--- src/items/modules.md | 4 +-- src/items/static-items.md | 10 +++--- src/items/traits.md | 58 +++++++++++++++++------------------ src/items/type-aliases.md | 8 ++--- src/items/unions.md | 8 ++--- src/items/use-declarations.md | 42 +++++++++++++------------ 15 files changed, 129 insertions(+), 151 deletions(-) diff --git a/src/items.md b/src/items.md index e3763d4..d573349 100644 --- a/src/items.md +++ b/src/items.md @@ -44,43 +44,18 @@ execution, and may reside in read-only memory. r[items.kinds] There are several kinds of items: -r[items.kind-modules] * [modules] - -r[items.kind-extern-crate] * [`extern crate` declarations] - -r[items.kind-use] * [`use` declarations] - -r[items.kind-fn] * [function definitions] - -r[items.kind-type] * [type definitions] - -r[items.kind-struct] * [struct definitions] - -r[items.kind-enum] * [enumeration definitions] - -r[items.kind-union] * [union definitions] - -r[items.kind-const] * [constant items] - -r[items.kind-static] * [static items] - -r[items.kind-trait] * [trait definitions] - -r[items.kind-impl] * [implementations] - -r[items.kind-extern] * [`extern` blocks] r[items.locations] diff --git a/src/items/associated-items.md b/src/items/associated-items.md index d7ba4ea..3df2e0e 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -13,7 +13,7 @@ r[items.associated.syntax] r[items.associated.intro] *Associated Items* are the items declared in [traits] or defined in [implementations]. They are called this because they are defined on an associate -type — the type in the implementation +type — the type in the implementation. r[items.associated.kinds] They are a subset of the kinds of items you can declare in a module. @@ -52,7 +52,7 @@ function body is replaced with a `;`. r[items.associated.name] The identifier is the name of the function. -r[items.associated.constraint] +r[items.associated.same-signature] The generics, parameter list, return type, and where clause of the associated function must be the same as the associated function declarations's. @@ -111,7 +111,7 @@ Associated functions whose first parameter is named `self` are called *methods* and may be invoked using the [method call operator], for example, `x.foo()`, as well as the usual function call notation. -r[items.associated.fn.method.constraint] +r[items.associated.fn.method.self-ty] If the type of the `self` parameter is specified, it is limited to types resolving to one generated by the following grammar (where `'lt` denotes some arbitrary lifetime): @@ -121,7 +121,6 @@ P = &'lt S | &'lt mut S | Box | Rc | Arc | Pin

    S = Self | P ``` -r[items.associated.fn.method.self-ty] The `Self` terminal in this grammar denotes a type resolving to the implementing type. This can also include the contextual type alias `Self`, other type aliases, or associated type projections resolving to the implementing type. @@ -214,7 +213,7 @@ let circle_shape = Circle::new(); let bounding_box = circle_shape.bounding_box(); ``` -r[items.associated.fn.params-edition2015] +r[items.associated.fn.params.edition2015] > **Edition differences**: In the 2015 edition, it is possible to declare trait > methods with anonymous parameters (e.g. `fn foo(u8)`). This is deprecated and > an error as of the 2018 edition. All parameters must have an argument name. @@ -233,7 +232,7 @@ r[items.associated.type] r[items.associated.type.intro] *Associated types* are [type aliases] associated with another type. -r[items.associated.type.constraint] +r[items.associated.type.restrictions] Associated types cannot be defined in [inherent implementations] nor can they be given a default implementation in traits. @@ -256,9 +255,9 @@ type Assoc: Bounds where WhereBounds; ``` r[items.associated.type.name] -The identifier is the name of the declared type alias +The identifier is the name of the declared type alias. -r[items.associated.type.constraint-impl] +r[items.associated.type.impl-fulfillment] The optional trait bounds must be fulfilled by the implementations of the type alias. r[items.associated.type.sized] @@ -268,7 +267,7 @@ r[items.associated.type.def] An *associated type definition* defines a type alias for the implementation of a trait on a type -r[items.associated.type.restriction-def] +r[items.associated.type.def.restriction] They are written similarly to an *associated type declaration*, but cannot contain `Bounds`, but instead must contain a `Type`: @@ -405,7 +404,7 @@ where clauses, dependent on functions in the trait and how the GAT is used. Thes rules may be loosened in the future; updates can be found [on the generic associated types initiative repository](https://rust-lang.github.io/generic-associated-types-initiative/explainer/required_bounds.html). -r[items.associated.type.generic-where-clause.constraint-valid-fn] +r[items.associated.type.generic-where-clause.valid-fn] In a few words, these where clauses are required in order to maximize the allowed definitions of the associated type in impls. To do this, any clauses that *can be proven to hold* on functions (using the parameters of the function or trait) @@ -422,7 +421,7 @@ In the above, on the `next` function, we can prove that `Self: 'a`, because of the implied bounds from `&'a mut self`; therefore, we must write the equivalent bound on the GAT itself: `where Self: 'x`. -r[items.associated.type.generic-where-clause.constraint-intersection] +r[items.associated.type.generic-where-clause.intersection] When there are multiple functions in a trait that use the GAT, then the *intersection* of the bounds from the different functions are used, rather than the union. @@ -440,7 +439,7 @@ know that `T: 'a` on `create_checker`, we do not know that on `do_check`. Howeve if `do_check` was commented out, then the `where T: 'x` bound would be required on `Checker`. -r[items.associated.type.generic-where-clause.constraint-forward] +r[items.associated.type.generic-where-clause.forward] The bounds on associated types also propagate required where clauses. ```rust diff --git a/src/items/constant-items.md b/src/items/constant-items.md index 5333455..b80b145 100644 --- a/src/items/constant-items.md +++ b/src/items/constant-items.md @@ -11,7 +11,7 @@ r[items.const.intro] A *constant item* is an optionally named _[constant value]_ which is not associated with a specific memory location in the program. -r[items.const.behaviour] +r[items.const.behavior] Constants are essentially inlined wherever they are used, meaning that they are copied directly into the relevant context when used. This includes usage of constants from external crates, and non-[`Copy`] types. References to the same constant are not necessarily @@ -48,7 +48,7 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { }; ``` -r[items.const.restriction] +r[items.const.expr-omission] The constant expression may only be omitted in a [trait definition]. ## Constants with Destructors diff --git a/src/items/enumerations.md b/src/items/enumerations.md index d2441a1..f20c77d 100644 --- a/src/items/enumerations.md +++ b/src/items/enumerations.md @@ -2,7 +2,7 @@ r[items.enum] -r[items.enum.sybtax] +r[items.enum.syntax] > **Syntax**\ > _Enumeration_ :\ >    `enum` @@ -128,7 +128,7 @@ let z = StructLike { value: 123 }; // Struct expression. r[items.enum.discriminant] -r[items.enum.discrimnant.intro] +r[items.enum.discriminant.intro] Each enum instance has a _discriminant_: an integer logically associated to it that is used to determine which variant it holds. @@ -150,7 +150,7 @@ following the variant name with `=` and a [constant expression]: r[items.enum.discriminant.explicit.unit-only] 1. if the enumeration is "[unit-only]". -r[items.enum.discriminan.explicit.primitive-repr] +r[items.enum.discriminant.explicit.primitive-repr] 2. if a [primitive representation] is used. For example: ```rust @@ -187,9 +187,9 @@ assert_eq!(baz_discriminant, 123); #### Restrictions -r[items.enum.discriminant.constraints] +r[items.enum.discriminant.restrictions] -r[items.enum.discrimnant.constraints.same-discriminant] +r[items.enum.discriminant.restrictions.same-discriminant] It is an error when two variants share the same discriminant. ```rust,compile_fail @@ -205,7 +205,7 @@ enum SharedDiscriminantError2 { } ``` -r[items.enum.discrimnant.constraints.above-max-discriminant] +r[items.enum.discriminant.restrictions.above-max-discriminant] It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant. @@ -254,7 +254,7 @@ assert_eq!(1, Enum::Bar as isize); assert_eq!(2, Enum::Baz as isize); ``` -r[items.enum.discriminant.coercion.constraint] +r[items.enum.discriminant.coercion.fieldless] [Field-less enums] can be casted if they do not have explicit discriminants, or where only unit variants are explicit. ```rust @@ -338,7 +338,7 @@ let y: u32 = x; // mismatched type error ## Variant visibility -r[items.enum.constraint-variant-visibility] +r[items.enum.variant-visibility] Enum variants syntactically allow a [_Visibility_] annotation, but this is rejected when the enum is validated. This allows items to be parsed with a diff --git a/src/items/extern-crates.md b/src/items/extern-crates.md index b052293..85f1063 100644 --- a/src/items/extern-crates.md +++ b/src/items/extern-crates.md @@ -25,7 +25,7 @@ Additionally, if the `extern crate` appears in the crate root, then the crate na r[items.extern-crate.as] The `as` clause can be used to bind the imported crate to a different name. -r[items.exter-crate.lookup] +r[items.extern-crate.lookup] The external crate is resolved to a specific `soname` at compile time, and a runtime linkage requirement to that `soname` is passed to the linker for loading at runtime. The `soname` is resolved at compile time by scanning the diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 6cb49f0..5839f24 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -21,7 +21,7 @@ External blocks provide _declarations_ of items that are not _defined_ in the current crate and are the basis of Rust's foreign function interface. These are akin to unchecked imports. -r[items.extern.restriction] +r[items.extern.allowed-kinds] Two kinds of item _declarations_ are allowed in external blocks: [functions] and [statics]. @@ -38,10 +38,13 @@ r[items.extern.fn] r[items.extern.fn.body] Functions within external blocks are declared in the same way as other Rust functions, with the exception that they must not have a body and are instead -terminated by a semicolon +terminated by a semicolon. -r[items.extern.fn.restriction] -Patterns are not allowed in parameters, only [IDENTIFIER] or `_` may be used. The `safe` and `unsafe` function qualifiers are +r[items.extern.fn.param-patterns] +Patterns are not allowed in parameters, only [IDENTIFIER] or `_` may be used. + +r[items.extern.fn.qualifiers] +The `safe` and `unsafe` function qualifiers are allowed, but other function qualifiers (e.g. `const`, `async`, `extern`) are not. @@ -200,19 +203,19 @@ r[items.extern.attributes.link.raw-dylib] an import library to link against (see [`dylib` versus `raw-dylib`] below for details). This is only valid for Windows targets. -r[items.extern.attributes.link.constraint] +r[items.extern.attributes.link.name-requirement] The `name` key must be included if `kind` is specified. r[items.extern.attributes.link.modifiers] The optional `modifiers` argument is a way to specify linking modifiers for the library to link. -r[items.extern.attributes.link.modifiers-syntax] +r[items.extern.attributes.link.modifiers.syntax] Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. -r[items.extern.attributes.link.modifiers-constraint] +r[items.extern.attributes.link.modifiers.multiple] Specifying multiple `modifiers` arguments in a single `link` attribute, or multiple identical modifiers in the same `modifiers` argument is not currently supported. \ Example: `#[link(name = "mylib", kind = "static", modifiers = "+whole-archive")]`. @@ -249,18 +252,18 @@ block. #### Linking modifiers: `bundle` -r[items.extern.attributes.link.modifier-bundle] +r[items.extern.attributes.link.modifiers.bundle] -r[items.extern.attributes.link.modifier-bundle.constraint] +r[items.extern.attributes.link.modifiers.bundle.allowed-kinds] This modifier is only compatible with the `static` linking kind. Using any other kind will result in a compiler error. -r[items.extern.attributes.link.modifier-bundle.behaviour] +r[items.extern.attributes.link.modifiers.bundle.behavior] When building a rlib or staticlib `+bundle` means that the native static library will be packed into the rlib or staticlib archive, and then retrieved from there during linking of the final binary. -r[items.extern.attributes.link.modifier-bundle.behaviour-negative] +r[items.extern.attributes.link.modifiers.bundle.behavior-negative] When building a rlib `-bundle` means that the native static library is registered as a dependency of that rlib "by name", and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking. \ @@ -268,10 +271,10 @@ When building a staticlib `-bundle` means that the native static library is simp into the archive and some higher level build system will need to add it later during linking of the final binary. -r[items.extern.attributes.link.modifier-bundle.no-effect] +r[items.extern.attributes.link.modifiers.bundle.no-effect] This modifier has no effect when building other targets like executables or dynamic libraries. -r[items.extern.attributes.link.modifier-bundle.default] +r[items.extern.attributes.link.modifiers.bundle.default] The default for this modifier is `+bundle`. More implementation details about this modifier can be found in @@ -279,17 +282,17 @@ More implementation details about this modifier can be found in #### Linking modifiers: `whole-archive` -r[items.extern.attributes.link.modifier-whole-archive] +r[items.extern.attributes.link.modifiers.whole-archive] -r[items.extern.attributes.link.modifier-whole-archive.constraint] +r[items.extern.attributes.link.modifiers.whole-archive.allowed-kinds] This modifier is only compatible with the `static` linking kind. Using any other kind will result in a compiler error. -r[items.extern.attributes.link.modifier-whole-archive.behaviour] +r[items.extern.attributes.link.modifiers.whole-archive.behavior] `+whole-archive` means that the static library is linked as a whole archive without throwing any object files away. -r[items.extern.attributes.link.modifier-whole-archive.default] +r[items.extern.attributes.link.modifiers.whole-archive.default] The default for this modifier is `-whole-archive`. More implementation details about this modifier can be found in @@ -297,21 +300,21 @@ More implementation details about this modifier can be found in ### Linking modifiers: `verbatim` -r[items.extern.attributes.link.modifier-verbatim] +r[items.extern.attributes.link.modifiers.verbatim] -r[items.extern.attributes.link.modifier-verbatim.constraint] +r[items.extern.attributes.link.modifiers.verbatim.allowed-kinds] This modifier is compatible with all linking kinds. -r[items.extern.attributes.link.modifier-verbatim.behaviour] +r[items.extern.attributes.link.modifiers.verbatim.behavior] `+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker. -r[items.extern.attributes.link.modifier-verbatim.behaviour-negative] +r[items.extern.attributes.link.modifiers.verbatim.behavior-negative] `-verbatim` means that rustc will either add a target-specific prefix and suffix to the library name before passing it to linker, or won't prevent linker from implicitly adding it. -r[items.extern.attributes.link.modifier-verbatim.default] +r[items.extern.attributes.link.modifiers.verbatim.default] The default for this modifier is `-verbatim`. More implementation details about this modifier can be found in @@ -420,7 +423,7 @@ unsafe extern "stdcall" { } ``` -r[items.extern.attributes.link_ordinal.constraints] +r[items.extern.attributes.link_ordinal.allowed-kinds] This attribute is only used with the `raw-dylib` linking kind. Using any other kind will result in a compiler error. diff --git a/src/items/functions.md b/src/items/functions.md index 3b258d1..8300ad1 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -75,7 +75,7 @@ fn answer_to_life_the_universe_and_everything() -> i32 { } ``` -r[items.fn.constraint-safety-qualifiers] +r[items.fn.safety-qualifiers] The `safe` function is semantically only allowed when used in an [`extern` block]. ## Function parameters @@ -94,7 +94,7 @@ r[items.fn.params.self-pat] If the first parameter is a _SelfParam_, this indicates that the function is a [method]. -r[items.fn.params.self-constraint] +r[items.fn.params.self-restriction] Functions with a self parameter may only appear as an [associated function] in a [trait] or [implementation]. @@ -125,7 +125,7 @@ return { }; ``` -r[items.fn.body.restriction] +r[items.fn.body.bodyless] Functions without a body block are terminated with a semicolon. This form may only appear in a [trait] or [external block]. @@ -271,7 +271,7 @@ Functions qualified with the `const` keyword are [const functions], as are [tuple struct] and [tuple variant] constructors. _Const functions_ can be called from within [const contexts]. -r[item.fn.const.extern] +r[items.fn.const.extern] Const functions may use the [`extern`] function qualifier. r[items.fn.const.exclusivity] @@ -320,7 +320,7 @@ fn example<'a>(x: &'a str) -> impl Future + 'a { r[items.fn.async.desugar] The actual desugaring is more complex: -r[items.fn.async.lifetime-catpure] +r[items.fn.async.lifetime-capture] - The return type in the desugaring is assumed to capture all lifetime parameters from the `async fn` declaration. This can be seen in the desugared example above, which explicitly outlives, and hence @@ -373,7 +373,6 @@ async fn safe_example() { } ``` -r[items.fn.async.safety.] Note that this behavior is a consequence of the desugaring to a function that returns an `impl Future` -- in this case, the function we desugar to is an `unsafe` function, but the return value remains diff --git a/src/items/generics.md b/src/items/generics.md index 498de74..feb84ee 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -30,7 +30,7 @@ implementations, which don't have a name, they come directly after `impl`. r[items.generics.syntax.decl-order] The order of generic parameters is restricted to lifetime parameters and then type and const parameters intermixed. -r[items.generics.syntax.constraint] +r[items.generics.syntax.duplicate-params] The same parameter name may not be declared more than once in a _GenericParams_ list. Some examples of items with type, const, and lifetime parameters: @@ -54,7 +54,7 @@ r[items.generics.builtin-generic-types] [function pointers] have lifetime or type parameters as well, but are not referred to with path syntax. -r[items.generics.constraint-widlcard-lifetime] +r[items.generics.wildcard-lifetime] `'_` is not a valid lifetime parameter. ### Const generics @@ -67,7 +67,7 @@ r[items.generics.const.intro] r[items.generics.const.namespace] The const identifier introduces a name in the [value namespace] for the constant parameter, and all instances of the item must be instantiated with a value of the given type. -r[items.generics.const.constraint] +r[items.generics.const.allowed-types] The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`. @@ -129,7 +129,7 @@ fn foo() { } ``` -r[items.generics.const.constraint-const-expr] +r[items.generics.const.standalone] As a further restriction, const parameters may only appear as a standalone argument inside of a [type] or [array repeat expression]. In those contexts, they may only be used as a single segment [path expression], possibly inside a @@ -150,7 +150,7 @@ fn bad_function() -> [u8; {N + 1}] { r[items.generics.const.argument] A const argument in a [path] specifies the const value to use for that item. -r[items.generics.const.argument-restriction] +r[items.generics.const.argument.const-expr] The argument must be a [const expression] of the type ascribed to the const parameter. The const expression must be a [block expression][block] (surrounded with braces) unless it is a single path segment (an [IDENTIFIER]) @@ -256,7 +256,7 @@ r[items.generics.where.intro] parameters as well as a way to specify bounds on types that aren't type parameters. -r[items.generics.where.higher-ranked-;ifetimes] +r[items.generics.where.higher-ranked-lifetimes] The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only allows [_LifetimeParam_] parameters. diff --git a/src/items/implementations.md b/src/items/implementations.md index 6f631f3..5bde1ec 100644 --- a/src/items/implementations.md +++ b/src/items/implementations.md @@ -51,10 +51,10 @@ r[items.impl.inherent.associated-items] Inherent implementations associate the contained items to the implementing type. -r[items.impl.inherent.values] +r[items.impl.inherent.associated-items.allowed-items] Inherent implementations can contain [associated functions] (including [methods]) and [associated constants]. -r[items.impl.inherent.constraint-type-alias] +r[items.impl.inherent.type-alias] They cannot contain associated type aliases. r[items.impl.inherent.associated-item-path] @@ -115,7 +115,7 @@ r[items.impl.trait.implemented-trait] The trait is known as the _implemented trait_. The implementing type implements the implemented trait. -r[items.impl.trait.constraint] +r[items.impl.trait.def-requirement] A trait implementation must define all non-default associated items declared by the implemented trait, may redefine default associated items defined by the implemented trait, and cannot define any other items. @@ -226,7 +226,7 @@ least once in one of: * As an [associated type] in the [bounds] of a type that contains another parameter that constrains the implementation -r[items.impl.generics.constraint] +r[items.impl.generics.constrain] Type and const parameters must always constrain the implementation. Lifetimes must constrain the implementation if the lifetime is used in an associated type. diff --git a/src/items/modules.md b/src/items/modules.md index 3244aad..c8fd4c8 100644 --- a/src/items/modules.md +++ b/src/items/modules.md @@ -45,11 +45,11 @@ mod math { r[items.mod.namespace] Modules are defined in the [type namespace] of the module or block where they are located. -r[items.mod.namespace-def] +r[items.mod.multiple-items] It is an error to define multiple items with the same name in the same namespace within a module. See the [scopes chapter] for more details on restrictions and shadowing behavior. -r[items.mod.constraint] +r[items.mod.unsafe] The `unsafe` keyword is syntactically allowed to appear before the `mod` keyword, but it is rejected at a semantic level. This allows macros to consume the syntax and make use of the `unsafe` keyword, before removing it from the diff --git a/src/items/static-items.md b/src/items/static-items.md index 5589071..f7e4773 100644 --- a/src/items/static-items.md +++ b/src/items/static-items.md @@ -36,17 +36,17 @@ r[items.static.safety] All access to a static is safe, but there are a number of restrictions on statics: -r[items.static.constraint-sync] +r[items.static.sync] * The type must have the `Sync` trait bound to allow thread-safe access. -r[items.static.constraint-const] +r[items.static.const] * Constants cannot refer to statics. -r[items.static.restriction-init] +r[items.static.init.omission] The initializer expression must be omitted in an [external block], and must be provided for free static items. -r[items.static.constraint-safety-qualifier] +r[items.static.safety-qualifiers] The `safe` and `unsafe` qualifiers are semantically only allowed when used in an [external block]. ## Statics & generics @@ -147,7 +147,7 @@ fn bump_levels_safe() -> u32 { } ``` -r[items.static.mut.constraints] +r[items.static.mut.sync] Mutable statics have the same restrictions as normal statics, except that the type does not have to implement the `Sync` trait. diff --git a/src/items/traits.md b/src/items/traits.md index a16ad01..dd315e4 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -1,8 +1,8 @@ # Traits -r[items.trait] +r[items.traits] -r[items.trait.syntax] +r[items.traits.syntax] > **Syntax**\ > _Trait_ :\ >    `unsafe`? `trait` [IDENTIFIER]  @@ -13,7 +13,7 @@ r[items.trait.syntax] >      [_AssociatedItem_]\*\ >    `}` -r[items.trait.intro] +r[items.traits.intro] A _trait_ describes an abstract interface that types can implement. This interface consists of [associated items], which come in three varieties: @@ -21,22 +21,22 @@ interface consists of [associated items], which come in three varieties: - [types](associated-items.md#associated-types) - [constants](associated-items.md#associated-constants) -r[items.trait.namespace] +r[items.traits.namespace] The trait declaration defines a trait in the [type namespace] of the module or block where it is located. -r[items.trait.associated-item-namespaces] +r[items.traits.associated-item-namespaces] Associated items are defined as members of the trait within their respective namespaces. Associated types are defined in the type namespace. Associated constants and associated functions are defined in the value namespace. -r[items.trait.self-param] +r[items.traits.self-param] All traits define an implicit type parameter `Self` that refers to "the type that is implementing this interface". Traits may also contain additional type parameters. These type parameters, including `Self`, may be constrained by other traits and so forth [as usual][generics]. -r[items.trait.impls] +r[items.traits.impls] Traits are implemented for specific types through separate [implementations]. -r[items.trait.associated-item-decls] +r[items.traits.associated-item-decls] Trait functions may omit the function body by replacing it with a semicolon. This indicates that the implementation must define the function. If the trait function defines a body, this definition acts as a default for any @@ -56,7 +56,7 @@ trait Example { } ``` -r[items.trait.fn-constraint] +r[items.traits.const-fn] Trait functions are not allowed to be [`const`]. ## Trait bounds @@ -83,25 +83,25 @@ trait Seq { ## Dyn compatibility -r[items.trait.dyn-compatible] +r[items.traits.dyn-compatible] -r[items.trait.dyn-compatible.intro] +r[items.traits.dyn-compatible.intro] A dyn-compatible trait can be the base trait of a [trait object]. A trait is *dyn compatible* if it has the following qualities: -r[items.trait.dyn-compatible.supertraits] +r[items.traits.dyn-compatible.supertraits] * All [supertraits] must also be dyn compatible. -r[items.trait.dyn-compatible.sized] +r[items.traits.dyn-compatible.sized] * `Sized` must not be a [supertrait][supertraits]. In other words, it must not require `Self: Sized`. -r[items.trait.dyn-compatible.associated-consts] +r[items.traits.dyn-compatible.associated-consts] * It must not have any associated constants. -r[items.trait.dyn-compatible.associated-types] +r[items.traits.dyn-compatible.associated-types] * It must not have any associated types with generics. -r[items.trait.dyn-compatible.associated-functions] +r[items.traits.dyn-compatible.associated-functions] * All associated functions must either be dispatchable from a trait object or be explicitly non-dispatchable: * Dispatchable functions must: * Not have any type parameters (although lifetime parameters are allowed). @@ -206,19 +206,19 @@ let obj: Box = Box::new(S); // ERROR: cannot use `Self` type param ## Supertraits -r[items.trait.supertraits] +r[items.traits.supertraits] -r[items.trait.supertraits.intro] +r[items.traits.supertraits.intro] **Supertraits** are traits that are required to be implemented for a type to implement a specific trait. Furthermore, anywhere a [generic][generics] or [trait object] is bounded by a trait, it has access to the associated items of its supertraits. -r[items.trait.supertraits.decl] +r[items.traits.supertraits.decl] Supertraits are declared by trait bounds on the `Self` type of a trait and transitively the supertraits of the traits declared in those trait bounds. It is an error for a trait to be its own supertrait. -r[items.trait.supertraits.subtrait] +r[items.traits.supertraits.subtrait] The trait with a supertrait is called a **subtrait** of its supertrait. The following is an example of declaring `Shape` to be a supertrait of `Circle`. @@ -277,9 +277,9 @@ let nonsense = circle.radius() * circle.area(); ## Unsafe traits -r[items.trait.safety] +r[items.traits.safety] -r[items.trait.safety.intro] +r[items.traits.safety.intro] Traits items that begin with the `unsafe` keyword indicate that *implementing* the trait may be [unsafe]. It is safe to use a correctly implemented unsafe trait. The [trait implementation] must also begin with the `unsafe` keyword. @@ -288,15 +288,15 @@ The [trait implementation] must also begin with the `unsafe` keyword. ## Parameter patterns -r[items.trait.params] +r[items.traits.params] -r[items.trait.params.constraint] +r[items.traits.params.allowed-patterns] Function or method declarations without a body only allow [IDENTIFIER] or `_` [wild card][WildcardPattern] patterns. `mut` [IDENTIFIER] is currently allowed, but it is deprecated and will become a hard error in the future. -r[items.trait.params.edition2015] +r[items.traits.params.edition2015] In the 2015 edition, the pattern for a trait function or method parameter is optional: @@ -307,7 +307,7 @@ trait T { } ``` -r[items.trait.params.restriction] +r[items.traits.params.restriction] The kinds of patterns for parameters is limited to one of the following: * [IDENTIFIER] @@ -316,7 +316,7 @@ The kinds of patterns for parameters is limited to one of the following: * `&` [IDENTIFIER] * `&&` [IDENTIFIER] -r[items.trait.params.restriction-edition2018] +r[items.traits.params.restriction.edition2018] Beginning in the 2018 edition, function or method parameter patterns are no longer optional. Also, all irrefutable patterns are allowed as long as there is a body. Without a body, the limitations listed above are still in effect. @@ -330,9 +330,9 @@ trait T { ## Item visibility -r[items.trait.associated-visibility] +r[items.traits.associated-visibility] -r[items.trait.associated-visibility.intro] +r[items.traits.associated-visibility.intro] Trait items syntactically allow a [_Visibility_] annotation, but this is rejected when the trait is validated. This allows items to be parsed with a unified syntax across different contexts where they are used. As an example, diff --git a/src/items/type-aliases.md b/src/items/type-aliases.md index 4346395..d496b8c 100644 --- a/src/items/type-aliases.md +++ b/src/items/type-aliases.md @@ -22,7 +22,7 @@ type Point = (u8, u8); let p: Point = (41, 68); ``` -r[items.type.constraint-constructor] +r[items.type.constructor-alias] A type alias to a tuple-struct or unit-struct cannot be used to qualify that type's constructor: ```rust,compile_fail @@ -35,15 +35,15 @@ let _ = UseAlias(5); // OK let _ = TypeAlias(5); // Doesn't work ``` -r[items.type.constraint] +r[items.type.associated-type] A type alias, when not used as an [associated type], must include a [_Type_] and may not include [_TypeParamBounds_]. -r[items.type.constraint-associated-trait] +r[items.type.associated-trait] A type alias, when used as an [associated type] in a [trait], must not include a [_Type_] specification but may include [_TypeParamBounds_]. -r[items.type.constraint-associated-impl] +r[items.type.associated-impl] A type alias, when used as an [associated type] in a [trait impl], must include a [_Type_] specification and may not include [_TypeParamBounds_]. diff --git a/src/items/unions.md b/src/items/unions.md index f1e696a..835f924 100644 --- a/src/items/unions.md +++ b/src/items/unions.md @@ -28,7 +28,7 @@ The key property of unions is that all fields of a union share common storage. As a result, writes to one field of a union can overwrite its other fields, and size of a union is determined by the size of its largest field. -r[items.union.field-constraints] +r[items.union.field-restrictions] Union field types are restricted to the following subset of types: r[items.union.field-copy] @@ -48,7 +48,7 @@ This restriction ensures, in particular, that union fields never need to be dropped. Like for structs and enums, it is possible to `impl Drop` for a union to manually define what happens when it gets dropped. -r[items.union.constraint] +r[items.union.fieldless] Unions without any fields are not accepted by the compiler, but can be accepted by macros. ## Initialization of a union @@ -92,7 +92,7 @@ r[items.union.fields.offset] Fields might have a non-zero offset (except when [the C representation] is used); in that case the bits starting at the offset of the fields are read -r[items.union.fields.precondition] +r[items.union.fields.validity] It is the programmer's responsibility to make sure that the data is valid at the field's type. Failing to do so results in [undefined behavior]. For example, reading the value `3` from a field of the [boolean type] is undefined behavior. Effectively, @@ -128,7 +128,7 @@ r[items.union.pattern] r[items.union.pattern.intro] Another way to access union fields is to use pattern matching. -r[items.union.pattern.constraint] +r[items.union.pattern.one-field] Pattern matching on union fields uses the same syntax as struct patterns, except that the pattern must specify exactly one field. diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index c66f073..ca70b8a 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -23,27 +23,27 @@ A `use` declaration is also sometimes called an _import_, or, if it is public, a [modules]: modules.md [blocks]: ../expressions/block-expr.md -r[items.use.modes] +r[items.use.forms] Use declarations support a number of convenient shortcuts: -r[items.use.mode-multiple] +r[items.use.forms.multiple] * Simultaneously binding a list of paths with a common prefix, using the brace syntax `use a::b::{c, d, e::f, g::h::i};` -r[items.use.mode-self] +r[items.use.forms.self] * Simultaneously binding a list of paths with a common prefix and their common parent module, using the `self` keyword, such as `use a::b::{self, c, d::e};` -r[items.use.mode-as] +r[items.use.forms.as] * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`. This can also be used with the last two features: `use a::b::{self as ab, c as abc}`. -r[items.use.mode-glob] +r[items.use.forms.glob] * Binding all paths matching a given prefix, using the asterisk wildcard syntax `use a::b::*;`. -r[items.use.mode-nesting] +r[items.use.forms.nesting] * Nesting groups of the previous features multiple times, such as `use a::b::{self as ab, c, d::{*, e::f}};` @@ -72,7 +72,7 @@ fn main() { ## `use` Visibility -r[items.use.vis] +r[items.use.visibility] r[items.use.visibility.intro] Like items, `use` declarations are private to the containing module, by @@ -82,7 +82,7 @@ public `use` declaration can therefore _redirect_ some public name to a different target definition: even a definition with a private canonical path, inside a different module. -r[items.use.visibility.constraint] +r[items.use.visibility.unambiguous] If a sequence of such redirections form a cycle or cannot be resolved unambiguously, they represent a compile-time error. @@ -120,7 +120,7 @@ They may create bindings for: * [Attributes] * [Derive macros] -r[items.use.path.constraint] +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. r[items.use.path.namespace] @@ -197,7 +197,7 @@ Braces can be nested, creating a tree of paths, where each grouping of segments use std::collections::{BTreeSet, hash_map::{self, HashMap}}; ``` -r[items.use.multiple-syntax.sempty] +r[items.use.multiple-syntax.empty] An empty brace does not import anything, though the leading path is validated that it is accessible. @@ -309,8 +309,10 @@ mod clashing { } ``` -r[items.use.glob.restriction] +r[items.use.glob.last-segment-only] `*` cannot be used as the first or intermediate segments. + +r[items.use.glob.self-import] `*` cannot be used to import a module's contents into itself (such as `use self::*;`). r[items.use.glob.edition2015] @@ -368,23 +370,23 @@ m!(use std as _;); ## Restrictions -r[items.use.restriction] +r[items.use.restrictions] The following are restrictions for valid `use` declarations: -r[items.use.restriction.crate] +r[items.use.restrictions.crate] * `use crate;` must use `as` to define the name to which to bind the crate root. -r[items.use.restriction.self] +r[items.use.restrictions.self] * `use {self};` is an error; there must be a leading segment when using `self`. -r[items.use.restriction.duplicate-name] +r[items.use.restrictions.duplicate-name] * As with any item definition, `use` imports cannot create duplicate bindings of the same name in the same namespace in a module or block. -r[items.use.restriction.macro-crate] +r[items.use.restrictions.macro-crate] * `use` paths with `$crate` are not allowed in a [`macro_rules`] expansion. -r[items.use.restriction.variant] +r[items.use.restrictions.variant] * `use` paths cannot refer to enum variants through a [type alias]. For example: ```rust,compile_fail enum MyEnum { @@ -398,14 +400,14 @@ r[items.use.restriction.variant] ## Ambiguities -r[items.use.ambiguity] +r[items.use.ambiguities] > **Note**: This section is incomplete. -r[items.use.ambiguity.intro] +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.ambiguity.glob] +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: From 6f976ce2181186bd6ad431819308ccb269b87b79 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 1 Nov 2024 07:35:31 +0100 Subject: [PATCH 171/189] fix typo referring to 'Unsize' trait --- src/type-coercions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type-coercions.md b/src/type-coercions.md index 8215186..26e27eb 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -216,7 +216,7 @@ r[coerce.unsized.composite] * `Foo` is a struct. * `T` implements `Unsize`. * The last field of `Foo` has a type involving `T`. - * If that field has type `Bar`, then `Bar` implements `Unsized>`. + * If that field has type `Bar`, then `Bar` implements `Unsize>`. * T is not part of the type of any other fields. r[coerce.unsized.pointer] From 88f3c2878ba44bc117b66f89cb6c87b2f0930311 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 30 Oct 2024 07:45:29 -0700 Subject: [PATCH 172/189] Update lifetimes for pre-expansion validation --- src/items/generics.md | 7 +++---- src/tokens.md | 2 -- src/trait-bounds.md | 3 ++- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/items/generics.md b/src/items/generics.md index feb84ee..5fab8de 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -12,7 +12,7 @@ r[items.generics.syntax] >    [_OuterAttribute_]\* ( _LifetimeParam_ | _TypeParam_ | _ConstParam_ ) > > _LifetimeParam_ :\ ->    [LIFETIME_OR_LABEL] ( `:` [_LifetimeBounds_] )? +>    [_Lifetime_] ( `:` [_LifetimeBounds_] )? > > _TypeParam_ :\ >    [IDENTIFIER] ( `:` [_TypeParamBounds_]? )? ( `=` [_Type_] )? @@ -54,8 +54,8 @@ r[items.generics.builtin-generic-types] [function pointers] have lifetime or type parameters as well, but are not referred to with path syntax. -r[items.generics.wildcard-lifetime] -`'_` is not a valid lifetime parameter. +r[items.generics.invalid-lifetimes] +`'_` and `'_static` are not valid lifetime parameters. ### Const generics @@ -294,7 +294,6 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { ``` [IDENTIFIER]: ../identifiers.md -[LIFETIME_OR_LABEL]: ../tokens.md#lifetimes-and-loop-labels [_ForLifetimes_]: ../trait-bounds.md#higher-ranked-trait-bounds [_LifetimeParam_]: #generic-parameters diff --git a/src/tokens.md b/src/tokens.md index 774a73b..fe2b553 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -762,8 +762,6 @@ r[lex.token.life.syntax] > > LIFETIME_OR_LABEL :\ >       `'` [NON_KEYWORD_IDENTIFIER][identifier] -> _(not immediately followed by `'`)_\ ->    | `'_` > _(not immediately followed by `'`)_ r[lex.token.life.intro] diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 4a7636a..2ff8341 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -21,7 +21,8 @@ r[bound.syntax] > > _Lifetime_ :\ >       [LIFETIME_OR_LABEL]\ ->    | `'static` +>    | `'static`\ +>    | `'_` > > _UseBound_ :\ >    `use` _UseBoundGenericArgs_ From 8280ebc3977d47ec52efab443e3c68875478c75a Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 30 Oct 2024 06:21:38 -0700 Subject: [PATCH 173/189] Fix header link for The Rust Representation --- src/type-layout.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/type-layout.md b/src/type-layout.md index f16ac6d..c31510e 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -207,7 +207,8 @@ not change the layout of the fields themselves. For example, a struct with a `C` representation that contains a struct `Inner` with the default representation will not change the layout of `Inner`. -### The `Rust` Representation + +### The `Rust` Representation r[layout.repr.rust] From 4ca74b7de8e13583193523e7b211ba38bc397559 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 30 Oct 2024 06:27:48 -0700 Subject: [PATCH 174/189] Further remove the "default" representation This updates some more references to the "default" representation and instead refers to it directly as the "Rust" representation. This is intended to more consistently refer to the same concept. --- src/items/enumerations.md | 4 ++-- src/type-layout.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/items/enumerations.md b/src/items/enumerations.md index f20c77d..02b2b83 100644 --- a/src/items/enumerations.md +++ b/src/items/enumerations.md @@ -133,7 +133,7 @@ Each enum instance has a _discriminant_: an integer logically associated to it that is used to determine which variant it holds. r[items.enum.discriminant.repr-rust] -Under the [default representation], the discriminant is interpreted as +Under the [`Rust` representation], the discriminant is interpreted as an `isize` value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout. @@ -378,7 +378,6 @@ enum E { [`C` representation]: ../type-layout.md#the-c-representation [call expression]: ../expressions/call-expr.md [constant expression]: ../const_eval.md#constant-expressions -[default representation]: ../type-layout.md#the-default-representation [enumerated type]: ../types/enum.md [Field-less enums]: #field-less-enum [IDENTIFIER]: ../identifiers.md @@ -386,6 +385,7 @@ enum E { [numeric cast]: ../expressions/operator-expr.md#semantics [path expression]: ../expressions/path-expr.md [primitive representation]: ../type-layout.md#primitive-representations +[`Rust` representation]: ../type-layout.md#the-rust-representation [struct expression]: ../expressions/struct-expr.md [struct]: structs.md [type namespace]: ../names/namespaces.md diff --git a/src/type-layout.md b/src/type-layout.md index c31510e..5d04d2a 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -204,7 +204,7 @@ struct AlignedStruct { r[layout.repr.inter-field] The representation of a type can change the padding between fields, but does not change the layout of the fields themselves. For example, a struct with a -`C` representation that contains a struct `Inner` with the default +`C` representation that contains a struct `Inner` with the `Rust` representation will not change the layout of `Inner`. From 66b8c77c9c212b0766450ca8b95b70088b880eb6 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 5 Nov 2024 14:09:30 +0100 Subject: [PATCH 175/189] trait object constraint correction --- src/types/trait-object.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/trait-object.md b/src/types/trait-object.md index 7a72f33..3cd9103 100644 --- a/src/types/trait-object.md +++ b/src/types/trait-object.md @@ -24,7 +24,7 @@ Trait objects are written as the keyword `dyn` followed by a set of trait bounds, but with the following restrictions on the trait bounds. r[type.trait-object.constraint] -All traits except the first trait must be auto traits, there may not be more than one +All traits except one trait must be auto traits, there may not be more than one lifetime, and opt-out bounds (e.g. `?Sized`) are not allowed. Furthermore, paths to traits may be parenthesized. From a477391e2ba46ef7947308b16dfaa503e04b2c6d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Tue, 5 Nov 2024 13:51:51 -0800 Subject: [PATCH 176/189] Update wording to be "not more than one" --- src/types/trait-object.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/trait-object.md b/src/types/trait-object.md index 3cd9103..0c4c759 100644 --- a/src/types/trait-object.md +++ b/src/types/trait-object.md @@ -24,7 +24,7 @@ Trait objects are written as the keyword `dyn` followed by a set of trait bounds, but with the following restrictions on the trait bounds. r[type.trait-object.constraint] -All traits except one trait must be auto traits, there may not be more than one +There may not be more than one non-auto trait, no more than one lifetime, and opt-out bounds (e.g. `?Sized`) are not allowed. Furthermore, paths to traits may be parenthesized. From a08450e872a64163381d5ff244b11413114c16d6 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 10 Nov 2024 17:50:22 +0900 Subject: [PATCH 177/189] Add s390x to inline-assembly documentation --- src/inline-assembly.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 7822394..a8bbc41 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -16,6 +16,7 @@ Support for inline assembly is stable on the following architectures: - AArch64 - RISC-V - LoongArch +- s390x The compiler will emit an error if `asm!` is used on an unsupported target. @@ -249,6 +250,11 @@ Here is the list of currently supported register classes: | RISC-V | `vreg` | `v[0-31]` | Only clobbers | | LoongArch | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | | LoongArch | `freg` | `$f[0-31]` | `f` | +| s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | +| s390x | `reg_addr` | `r[1-10]`, `r[12-14]` | `a` | +| s390x | `freg` | `f[0-15]` | `f` | +| s390x | `vreg` | `v[0-31]` | Only clobbers | +| s390x | `areg` | `a[2-15]` | Only clobbers | > **Notes**: > - On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. @@ -288,6 +294,10 @@ The availability of supported types for a particular register class may depend o | RISC-V | `vreg` | N/A | Only clobbers | | LoongArch64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | | LoongArch64 | `freg` | None | `f32`, `f64` | +| s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` | +| s390x | `freg` | None | `f32`, `f64` | +| s390x | `vreg` | N/A | Only clobbers | +| s390x | `areg` | N/A | Only clobbers | > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). @@ -372,8 +382,8 @@ Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | -| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `$fp` (LoongArch) | The frame pointer cannot be used as an input or output. | +| All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | +| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `$fp` (LoongArch), `r11` (s390x) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | | All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `x9` (RISC-V), `$s8` (LoongArch) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | x86 | `ip` | This is the program counter, not a real register. | @@ -386,6 +396,8 @@ Some registers cannot be used for input or output operands: | LoongArch | `$r0` or `$zero` | This is a constant zero register which can't be modified. | | LoongArch | `$r2` or `$tp` | This is reserved for TLS. | | LoongArch | `$r21` | This is reserved by the ABI. | +| s390x | `c[0-15]` | Reserved by the kernel. | +| s390x | `a[0-1]` | Reserved for system use. | r[asm.register-names.fp-bp-reserved] The frame pointer and base pointer registers are reserved for internal use by LLVM. While `asm!` statements cannot explicitly specify the use of reserved registers, in some cases LLVM will allocate one of these reserved registers for `reg` operands. Assembly code making use of reserved registers should be careful since `reg` operands may use the same registers. @@ -441,6 +453,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | RISC-V | `freg` | None | `f0` | None | | LoongArch | `reg` | None | `$r1` | None | | LoongArch | `freg` | None | `$f0` | None | +| s390x | `reg` | None | `%r0` | None | +| s390x | `reg_addr` | None | `%r1` | None | +| s390x | `freg` | None | `%f0` | None | > **Notes**: > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register. @@ -485,6 +500,7 @@ The following ABIs can be used with `clobber_abi`: | ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` | | RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` | | LoongArch | `"C"`, `"system"` | `$r1`, `$r[4-20]`, `$f[0-23]` | +| s390x | `"C"`, `"system"` | `r[0-5]`, `r14`, `f[0-7]`, `v[0-31]`, `a[2-15]` | > Notes: > - On AArch64 `x18` only included in the clobber list if it is not considered as a reserved register on the target. @@ -624,6 +640,8 @@ r[asm.rules.preserved-registers] - Vector extension state (`vtype`, `vl`, `vcsr`). - LoongArch - Floating-point condition flags in `$fcc[0-7]`. + - s390x + - The condition code register `cc`. r[asm.rules.x86-df] - On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit. From 8ccaf6b6748123f8a5383036d9a73c2156e5675c Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 10 Nov 2024 07:14:00 +0900 Subject: [PATCH 178/189] Add Arm64EC to inline-assembly documentation --- src/inline-assembly.md | 46 +++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/inline-assembly.md b/src/inline-assembly.md index a8bbc41..a6cdb1e 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -13,7 +13,7 @@ r[asm.stable-targets] Support for inline assembly is stable on the following architectures: - x86 and x86-64 - ARM -- AArch64 +- AArch64 and Arm64EC - RISC-V - LoongArch - s390x @@ -235,6 +235,9 @@ Here is the list of currently supported register classes: | AArch64 | `vreg` | `v[0-31]` | `w` | | AArch64 | `vreg_low16` | `v[0-15]` | `x` | | AArch64 | `preg` | `p[0-15]`, `ffr` | Only clobbers | +| Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | +| Arm64EC | `vreg` | `v[0-15]` | `w` | +| Arm64EC | `vreg_low16` | `v[0-15]` | `x` | | ARM (ARM/Thumb2) | `reg` | `r[0-12]`, `r14` | `r` | | ARM (Thumb1) | `reg` | `r[0-7]` | `r` | | ARM | `sreg` | `s[0-31]` | `t` | @@ -283,6 +286,8 @@ The availability of supported types for a particular register class may depend o | AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | AArch64 | `vreg` | `neon` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
    `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
    `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | | AArch64 | `preg` | N/A | Only clobbers | +| Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | +| Arm64EC | `vreg` | `neon` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
    `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
    `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | | ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` | | ARM | `sreg` | `vfp2` | `i32`, `f32` | | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` | @@ -339,6 +344,12 @@ Here is the list of all supported register aliases: | AArch64 | `sp` | `wsp` | | AArch64 | `xzr` | `wzr` | | AArch64 | `v[0-31]` | `b[0-31]`, `h[0-31]`, `s[0-31]`, `d[0-31]`, `q[0-31]` | +| Arm64EC | `x[0-30]` | `w[0-30]` | +| Arm64EC | `x29` | `fp` | +| Arm64EC | `x30` | `lr` | +| Arm64EC | `sp` | `wsp` | +| Arm64EC | `xzr` | `wzr` | +| Arm64EC | `v[0-15]` | `b[0-15]`, `h[0-15]`, `s[0-15]`, `d[0-15]`, `q[0-15]` | | ARM | `r[0-3]` | `a[1-4]` | | ARM | `r[4-9]` | `v[1-6]` | | ARM | `r9` | `rfp` | @@ -383,12 +394,15 @@ Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `$fp` (LoongArch), `r11` (s390x) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `x29` (AArch64 and Arm64EC), `x8` (RISC-V), `$fp` (LoongArch), `r11` (s390x) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | -| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `x9` (RISC-V), `$s8` (LoongArch) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | +| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64 and Arm64EC), `x9` (RISC-V), `$s8` (LoongArch) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | x86 | `ip` | This is the program counter, not a real register. | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | AArch64 | `x18` | This is an OS-reserved register on some AArch64 targets. | +| Arm64EC | `xzr` | This is a constant zero register which can't be modified. | +| Arm64EC | `x18` | This is an OS-reserved register. | +| Arm64EC | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]`, `p[0-15]`, `ffr` | These are AArch64 registers that are not supported for Arm64EC. | | ARM | `pc` | This is the program counter, not a real register. | | ARM | `r9` | This is an OS-reserved register on some ARM targets. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | @@ -434,16 +448,16 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | x86 | `*mm_reg` | `y` | `ymm0` | `t` | | x86 | `*mm_reg` | `z` | `zmm0` | `g` | | x86 | `kreg` | None | `k1` | None | -| AArch64 | `reg` | None | `x0` | `x` | -| AArch64 | `reg` | `w` | `w0` | `w` | -| AArch64 | `reg` | `x` | `x0` | `x` | -| AArch64 | `vreg` | None | `v0` | None | -| AArch64 | `vreg` | `v` | `v0` | None | -| AArch64 | `vreg` | `b` | `b0` | `b` | -| AArch64 | `vreg` | `h` | `h0` | `h` | -| AArch64 | `vreg` | `s` | `s0` | `s` | -| AArch64 | `vreg` | `d` | `d0` | `d` | -| AArch64 | `vreg` | `q` | `q0` | `q` | +| AArch64/Arm64EC | `reg` | None | `x0` | `x` | +| AArch64/Arm64EC | `reg` | `w` | `w0` | `w` | +| AArch64/Arm64EC | `reg` | `x` | `x0` | `x` | +| AArch64/Arm64EC | `vreg` | None | `v0` | None | +| AArch64/Arm64EC | `vreg` | `v` | `v0` | None | +| AArch64/Arm64EC | `vreg` | `b` | `b0` | `b` | +| AArch64/Arm64EC | `vreg` | `h` | `h0` | `h` | +| AArch64/Arm64EC | `vreg` | `s` | `s0` | `s` | +| AArch64/Arm64EC | `vreg` | `d` | `d0` | `d` | +| AArch64/Arm64EC | `vreg` | `q` | `q0` | `q` | | ARM | `reg` | None | `r0` | None | | ARM | `sreg` | None | `s0` | None | | ARM | `dreg` | None | `d0` | `P` | @@ -497,6 +511,7 @@ The following ABIs can be used with `clobber_abi`: | x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[0-7]`, `st([0-7])`, `tmm[0-7]` | | x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[0-7]`, `st([0-7])`, `tmm[0-7]` | | AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x18`\*, `x30`, `v[0-31]`, `p[0-15]`, `ffr` | +| Arm64EC | `"C"`, `"system"` | `x[0-12]`, `x[15-17]`, `x30`, `v[0-15]` | | ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` | | RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` | | LoongArch | `"C"`, `"system"` | `$r1`, `$r[4-20]`, `$f[0-23]` | @@ -632,7 +647,7 @@ r[asm.rules.preserved-registers] - Condition flags in `FPSCR` (N, Z, C, V) - Saturation flag in `FPSCR` (QC) - Floating-point exception flags in `FPSCR` (IDC, IXC, UFC, OFC, DZC, IOC). - - AArch64 + - AArch64 and Arm64EC - Condition flags (`NZCV` register). - Floating-point status (`FPSR` register). - RISC-V @@ -651,6 +666,9 @@ r[asm.rules.x86-x87] - On x86, the x87 floating-point register stack must remain unchanged unless all of the `st([0-7])` registers have been marked as clobbered with `out("st(0)") _, out("st(1)") _, ...`. - If all x87 registers are clobbered then the x87 register stack is guaranteed to be empty upon entering an `asm` block. Assembly code must ensure that the x87 register stack is also empty when exiting the asm block. +r[asm.rules.arm64ec] +- On arm64ec, [call checkers with appropriate thunks](https://learn.microsoft.com/en-us/windows/arm/arm64ec-abi#authoring-arm64ec-in-assembly) are mandatory when calling functions. + r[asm.rules.only-on-exit] - The requirement of restoring the stack pointer and non-output registers to their original value only applies when exiting an `asm!` block. - This means that `asm!` blocks that never return (even if not marked `noreturn`) don't need to preserve these registers. From deec7d2edfd90444d134f35acd99e9719e3ccee0 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 24 Jun 2020 16:40:32 -0700 Subject: [PATCH 179/189] Explaining how to link mixed C/Rust binaries. --- src/linkage.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/linkage.md b/src/linkage.md index 894c5da..ff41a14 100644 --- a/src/linkage.md +++ b/src/linkage.md @@ -252,6 +252,23 @@ a statically linked binary on MSVC you would execute: RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-pc-windows-msvc ``` +## Mixed Rust and foreign codebases + +If you are mixing Rust with foreign code (e.g. C, C++) and wish to make a single +binary containing both types of code, you have two approaches for the final +binary link: + +* Use `rustc`. Pass any non-Rust libraries using `-L ` and `-l` + rustc arguments, and/or `#[link]` directives in your Rust code. If you need to + link against `.o` files you can use `-Clink-arg=file.o`. +* Use your foreign linker. In this case, you first need to generate a Rust `staticlib` + target and pass that into your foreign linker invocation. If you need to link + multiple Rust subsystems, you will need to generate a _single_ `staticlib` + perhaps using lots of `extern crate` statements to include multiple Rust `rlib`s. + Multiple Rust `staticlib` files are likely to conflict. + +Passing `rlib`s directly into your foreign linker is currently unsupported. + [`cfg` attribute `target_feature` option]: conditional-compilation.md#target_feature [configuration option]: conditional-compilation.md [procedural macros]: procedural-macros.md From 7953af5dea552b90d4f018a7265c70dca503b880 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Sun, 29 Sep 2019 19:06:30 +0200 Subject: [PATCH 180/189] Add examples to clarify the casting rules --- src/expressions/operator-expr.md | 82 ++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index a9e91f0..7b2f5f4 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -398,25 +398,88 @@ reference types and `mut` or `const` in pointer types. * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op (Rust uses 2's complement for negative values of fixed integers) + + ```rust + # #![allow(overflowing_literals)] + assert_eq!(42i8 as u8, 42u8); + assert_eq!(-1i8 as u8, 255u8); + assert_eq!(255u8 as i8, -1i8); + assert_eq!(0xffu8 as i8, 0xffi8); + assert_eq!(-1i16 as u16, 65535u16); + ``` + * Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will truncate + + ```rust + # #![allow(overflowing_literals)] + assert_eq!(42u16 as u8, 42u8); + assert_eq!(1234u16 as u8, 210u8); + assert_eq!(0xabcdu16 as u8, 0xcdu8); + + assert_eq!(-42i16 as i8, -42i8); + assert_eq!(1234u16 as i8, -46i8); + assert_eq!(0xabcdi16 as i8, 0xcdi8); + ``` + * Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will * zero-extend if the source is unsigned * sign-extend if the source is signed + + ```rust + # #![allow(overflowing_literals)] + assert_eq!(42i8 as i16, 42i16); + assert_eq!(-17i8 as i16, -17i16); + assert_eq!(0b1000_1010u8 as u16, 0b0000_0000_1000_1010u16, "Zero-extend"); + assert_eq!(0b0000_1010i8 as i16, 0b0000_0000_0000_1010i16, "Sign-extend 0"); + assert_eq!(0b1000_1010i8 as i16, 0b1111_1111_1000_1010i16, "Sign-extend 1"); + ``` + * Casting from a float to an integer will round the float towards zero * `NaN` will return `0` * Values larger than the maximum integer value, including `INFINITY`, will saturate to the maximum value of the integer type. * Values smaller than the minimum integer value, including `NEG_INFINITY`, will saturate to the minimum value of the integer type. + + ```rust + assert_eq!(42.9f32 as i32, 42); + assert_eq!(-42.9f32 as i32, -42); + assert_eq!(42_000_000f32 as i32, 42_000_000); + println!("Undefined Behavior: {}", 1_000_000_000_000_000f32 as i32); + println!("Undefined Behavior: {}", std::f32::NEG_INFINITY as i32); + println!("Undefined Behavior: {}", std::f32::NAN as i32); + ``` + * Casting from an integer to float will produce the closest possible float \* * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* * on overflow, infinity (of the same sign as the input) is produced * note: with the current set of numeric types, overflow can only happen on `u128 as f32` for values greater or equal to `f32::MAX + (0.5 ULP)` + + ```rust + assert_eq!(1337i32 as f32, 1337f32); + assert_eq!(123_456_789i32 as f32, 123_456_790f32, "Rounded"); + assert_eq!(0xffffffff_ffffffff_ffffffff_ffffffff_u128 as f32, std::f32::INFINITY); + ``` + * Casting from an f32 to an f64 is perfect and lossless + + ```rust + assert_eq!(1_234.5f32 as f64, 1_234.5f64); + assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY); + assert!((std::f32::NAN as f64).is_nan()); + ``` + * Casting from an f64 to an f32 will produce the closest possible f32 \*\* * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* * on overflow, infinity (of the same sign as the input) is produced + ```rust + assert_eq!(1_234.5f64 as f32, 1_234.5f32); + assert_eq!(1_234_567_891.123f64 as f32, 1_234_567_890f32, "Rounded"); + assert_eq!(std::f64::INFINITY as f32, std::f32::INFINITY); + assert!((std::f64::NAN as f32).is_nan()); + ``` + \* if integer-to-float casts with this rounding mode and overflow behavior are not supported natively by the hardware, these casts will likely be slower than expected. @@ -437,15 +500,34 @@ Casting is limited to the following kinds of enumerations: * [Unit-only enums] * [Field-less enums] without [explicit discriminants], or where only unit-variants have explicit discriminants +```rust +enum Enum { A, B, C } +assert_eq!(Enum::A as i32, 0); +assert_eq!(Enum::B as i32, 1); +assert_eq!(Enum::C as i32, 2); +``` + #### Primitive to integer cast * `false` casts to `0`, `true` casts to `1` * `char` casts to the value of the code point, then uses a numeric cast if needed. +```rust +assert_eq!(false as i32, 0); +assert_eq!(true as i32, 1); +assert_eq!('A' as i32, 65); +assert_eq!('Ö' as i32, 214); +``` + #### `u8` to `char` cast Casts to the `char` with the corresponding code point. +```rust +assert_eq!(65u8 as char, 'A'); +assert_eq!(214u8 as char, 'Ö'); +``` + #### Pointer to address cast Casting from a raw pointer to an integer produces the machine address of the referenced memory. From 657fbd00adec79737ad9da0b33f4a1e500814cc5 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 13 Nov 2024 19:51:30 -0800 Subject: [PATCH 181/189] Update example for changes in float behavior --- src/expressions/operator-expr.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 7b2f5f4..436cf41 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -444,9 +444,9 @@ reference types and `mut` or `const` in pointer types. assert_eq!(42.9f32 as i32, 42); assert_eq!(-42.9f32 as i32, -42); assert_eq!(42_000_000f32 as i32, 42_000_000); - println!("Undefined Behavior: {}", 1_000_000_000_000_000f32 as i32); - println!("Undefined Behavior: {}", std::f32::NEG_INFINITY as i32); - println!("Undefined Behavior: {}", std::f32::NAN as i32); + assert_eq!(std::f32::NAN as i32, 0); + assert_eq!(1_000_000_000_000_000f32 as i32, 0x7fffffffi32); + assert_eq!(std::f32::NEG_INFINITY as i32, -0x80000000i32); ``` * Casting from an integer to float will produce the closest possible float \* From 17f3e49c71d41afdb17f8be2b8e4283684bdd52d Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Wed, 13 Nov 2024 19:56:08 -0800 Subject: [PATCH 182/189] Avoid the use of overflowing_literals in the examples I think that it could have some potential confusion since it isn't displayed in the text that these are overflowing, and it requires an extra layer of reasoning needed to understand how it translates. --- src/expressions/operator-expr.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 436cf41..530d41d 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -400,11 +400,9 @@ reference types and `mut` or `const` in pointer types. (Rust uses 2's complement for negative values of fixed integers) ```rust - # #![allow(overflowing_literals)] assert_eq!(42i8 as u8, 42u8); assert_eq!(-1i8 as u8, 255u8); assert_eq!(255u8 as i8, -1i8); - assert_eq!(0xffu8 as i8, 0xffi8); assert_eq!(-1i16 as u16, 65535u16); ``` @@ -412,14 +410,13 @@ reference types and `mut` or `const` in pointer types. truncate ```rust - # #![allow(overflowing_literals)] assert_eq!(42u16 as u8, 42u8); assert_eq!(1234u16 as u8, 210u8); assert_eq!(0xabcdu16 as u8, 0xcdu8); assert_eq!(-42i16 as i8, -42i8); assert_eq!(1234u16 as i8, -46i8); - assert_eq!(0xabcdi16 as i8, 0xcdi8); + assert_eq!(0xabcdi32 as i8, -51i8); ``` * Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will @@ -427,12 +424,11 @@ reference types and `mut` or `const` in pointer types. * sign-extend if the source is signed ```rust - # #![allow(overflowing_literals)] assert_eq!(42i8 as i16, 42i16); assert_eq!(-17i8 as i16, -17i16); assert_eq!(0b1000_1010u8 as u16, 0b0000_0000_1000_1010u16, "Zero-extend"); assert_eq!(0b0000_1010i8 as i16, 0b0000_0000_0000_1010i16, "Sign-extend 0"); - assert_eq!(0b1000_1010i8 as i16, 0b1111_1111_1000_1010i16, "Sign-extend 1"); + assert_eq!(0b1000_1010u8 as i8 as i16, 0b1111_1111_1000_1010u16 as i16, "Sign-extend 1"); ``` * Casting from a float to an integer will round the float towards zero From e0ec92016683dd8bfbd01f7e59e6ef80812f3fa3 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Thu, 14 Nov 2024 08:57:30 +0100 Subject: [PATCH 183/189] fix typos --- src/conditional-compilation.md | 2 +- src/macro-ambiguity.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index bc655c4..5255bb8 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -238,7 +238,7 @@ on the endianness of the target's CPU. ### `target_pointer_width` -r[cfg.target_poitner_width] +r[cfg.target_pointer_width] r[cfg.target_pointer_width.general] Key-value option set once with the target's pointer width in bits. diff --git a/src/macro-ambiguity.md b/src/macro-ambiguity.md index ffdd796..159b867 100644 --- a/src/macro-ambiguity.md +++ b/src/macro-ambiguity.md @@ -11,7 +11,7 @@ of this text is copied, and expanded upon in subsequent RFCs. r[macro.ambiguity.convention] r[macro.ambiguity.convention.defs] - - `macro`: anything invokable as `foo!(...)` in source code. + - `macro`: anything invocable as `foo!(...)` in source code. - `MBE`: macro-by-example, a macro defined by `macro_rules`. - `matcher`: the left-hand-side of a rule in a `macro_rules` invocation, or a subportion thereof. From 60aa1a4e4e3dacbd72c9ce0830d90ef04b6ee1a3 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 15 Nov 2024 13:25:53 -0800 Subject: [PATCH 184/189] Fix various spelling and format errors --- src/attributes/codegen.md | 10 +++++----- src/attributes/diagnostics.md | 10 +++++----- src/attributes/testing.md | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 314b38f..4c5b966 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -21,7 +21,7 @@ have no effect on a trait function without a body. ### The `inline` attribute -r[attributes.codgen.inline] +r[attributes.codegen.inline] r[attributes.codegen.inline.intro] The *`inline` [attribute]* suggests that a copy of the attributed function @@ -46,7 +46,7 @@ There are three ways to use the inline attribute: ### The `cold` attribute -r[attribute.codegen.cold] +r[attributes.codegen.cold] The *`cold` [attribute]* suggests that the attributed function is unlikely to be called. @@ -93,13 +93,13 @@ be used with a `target_feature` attribute. ### Available features -r[attributes.codegen.target_features.availability] +r[attributes.codegen.target_feature.availability] The following is a list of the available feature names. #### `x86` or `x86_64` -r[attributes.codegen.target_features.x86] +r[attributes.codegen.target_feature.x86] Executing code with unsupported features is undefined behavior on this platform. Hence this platform requires that `#[target_feature]` is only applied to [`unsafe` @@ -482,7 +482,7 @@ r[attributes.codegen.instruction_set] r[attributes.codegen.instruction_set.restriction] The *`instruction_set` [attribute]* may be applied to a function to control which instruction set the function will be generated for. -r[attributes.codegen.instruction_set.behaviour] +r[attributes.codegen.instruction_set.behavior] This allows mixing more than one instruction set in a single program on CPU architectures that support it. r[attributes.codegen.instruction_set.syntax] diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 5e910c4..3a4b712 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -499,7 +499,7 @@ The following keys have the given meaning: * `label` --- The text for the label shown inline in the broken code in the error message. * `note` --- Provides additional notes. -r[attributes.diagnostic.on_unimplemented-note-repetition] +r[attributes.diagnostic.on_unimplemented.note-repetition] The `note` option can appear several times, which results in several note messages being emitted. r[attributes.diagnostic.on_unimplemented.repetition] @@ -509,18 +509,18 @@ r[attributes.diagnostic.on_unimplemented.warnings] Any other occurrence generates an lint warning. For any other non-existing option a lint-warning is generated. -r[attributes.diagnostic.format-string] +r[attributes.diagnostic.on_unimplemented.format-string] All three options accept a string as an argument, interpreted using the same formatting as a [`std::fmt`] string. -r[attributes.diagnostic.format-parameters] +r[attributes.diagnostic.on_unimplemented.format-parameters] Format parameters with the given named parameter will be replaced with the following text: * `{Self}` --- The name of the type implementing the trait. * `{` *GenericParameterName* `}` --- The name of the generic argument's type for the given generic parameter. -r[attributes.diagnostic.invalid-formats] +r[attributes.diagnostic.on_unimplemented.invalid-formats] Any other format parameter will generate a warning, but will otherwise be included in the string as-is. -r[attributes.diagnostic.invalid-string] +r[attributes.diagnostic.on_unimplemented.invalid-string] Invalid format strings may generate a warning, but are otherwise allowed, but may not display as intended. Format specifiers may generate a warning, but are otherwise ignored. diff --git a/src/attributes/testing.md b/src/attributes/testing.md index 5174d10..6051dea 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -31,7 +31,7 @@ Test functions must be free, monomorphic functions that take no arguments, and t > Note: The test mode is enabled by passing the `--test` argument to `rustc` > or using `cargo test`. -r[attributes.testing.success] +r[attributes.testing.test.success] The test harness calls the returned value's [`report`] method, and classifies the test as passed or failed depending on whether the resulting [`ExitCode`] represents successful termination. In particular: * Tests that return `()` pass as long as they terminate and do not panic. @@ -84,7 +84,7 @@ r[attributes.testing.should_panic.target] A function annotated with the `test` attribute that returns `()` can also be annotated with the `should_panic` attribute. -r[attributes.testing.should_panic.behaviour] +r[attributes.testing.should_panic.behavior] The *`should_panic` attribute* makes the test only pass if it actually panics. From 2684f6f5e2cab3fe3f9f9e37ed4215aa22f70521 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 15 Nov 2024 13:26:10 -0800 Subject: [PATCH 185/189] Add back some newlines that were removed --- src/attributes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/attributes.md b/src/attributes.md index 02588b2..d1034ec 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -48,6 +48,7 @@ The following attributes are unsafe: r[attributes.kind] Attributes can be classified into the following kinds: + * [Built-in attributes] * [Macro attributes][attribute macros] * [Derive macro helper attributes] @@ -55,6 +56,7 @@ Attributes can be classified into the following kinds: r[attributes.application] Attributes may be applied to many things in the language: + * All [item declarations] accept outer attributes while [external blocks], [functions], [implementations], and [modules] accept inner attributes. * Most [statements] accept outer attributes (see [Expression Attributes] for From 04f6c6a0ab9d7863133c8c59f18a24ad8cedc393 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 15 Nov 2024 13:26:42 -0800 Subject: [PATCH 186/189] Remove some double blank lines --- src/attributes.md | 1 - src/attributes/codegen.md | 1 - src/attributes/debugger.md | 2 -- src/attributes/derive.md | 1 - src/attributes/diagnostics.md | 1 - src/attributes/testing.md | 2 -- src/attributes/type_system.md | 1 - 7 files changed, 9 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index d1034ec..ee38dcd 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -109,7 +109,6 @@ fn some_unused_variables() { r[attributes.meta] - r[attributes.meta.intro] A "meta item" is the syntax used for the _Attr_ rule by most [built-in attributes]. It has the following grammar: diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 4c5b966..18fa36f 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -63,7 +63,6 @@ assumed to exist. r[attributes.codegen.target_feature] - r[attributes.codegen.target_feature.intro] The *`target_feature` [attribute]* may be applied to a function to enable code generation of that function for specific platform architecture diff --git a/src/attributes/debugger.md b/src/attributes/debugger.md index fb27af8..2521c4e 100644 --- a/src/attributes/debugger.md +++ b/src/attributes/debugger.md @@ -86,7 +86,6 @@ When viewed under WinDbg, the `fancy_rect` variable would be shown as follows: r[attributes.debugger.debugger_visualizer.gdb] - r[attributes.debugger.debugger_visualizer.gdb.pretty] GDB supports the use of a structured Python script, called a *pretty printer*, that describes how a type should be visualized in the debugger view. For detailed information on pretty printers, refer to GDB's [pretty printing documentation]. @@ -161,7 +160,6 @@ When the crate's debug executable is passed into GDB[^rust-gdb], `print bob` wil r[attributes.debugger.collapse_debuginfo] - r[attributes.debugger.collapse_debuginfo.intro] The *`collapse_debuginfo` [attribute]* controls whether code locations from a macro definition are collapsed into a single location associated with the macro's call site, when generating debuginfo for code calling this macro. diff --git a/src/attributes/derive.md b/src/attributes/derive.md index 07238c4..6a61dbf 100644 --- a/src/attributes/derive.md +++ b/src/attributes/derive.md @@ -2,7 +2,6 @@ r[attributes.derive] - r[attributes.derive.intro] The *`derive` attribute* allows new [items] to be automatically generated for data structures. diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 3a4b712..df7d166 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -492,7 +492,6 @@ The attribute should be placed on a [trait declaration], though it is not an err r[attributes.diagnostic.on_unimplemented.syntax] The attribute uses the [_MetaListNameValueStr_] syntax to specify its inputs, though any malformed input to the attribute is not considered as an error to provide both forwards and backwards compatibility. - r[attributes.diagnostic.on_unimplemented.keys] The following keys have the given meaning: * `message` --- The text for the top level error message. diff --git a/src/attributes/testing.md b/src/attributes/testing.md index 6051dea..2d4ffaf 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -11,7 +11,6 @@ enables the [`test` conditional compilation option]. r[attributes.testing.test] - r[attributes.testing.test.intro] The *`test` attribute* marks a function to be executed as a test. @@ -55,7 +54,6 @@ fn test_the_thing() -> io::Result<()> { r[attributes.testing.ignore] - r[attributes.testing.ignore.intro] A function annotated with the `test` attribute can also be annotated with the `ignore` attribute. The *`ignore` attribute* tells the test harness to not diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index bce1b8a..5325a88 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -8,7 +8,6 @@ The following [attributes] are used for changing how a type can be used. r[attributes.type-system.non_exhaustive] - r[attributes.type-system.non_exhaustive.intro] The *`non_exhaustive` attribute* indicates that a type or variant may have more fields or variants added in the future. From 72f7551c16c3d556f18a0ae2608bbd3930291e2e Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 15 Nov 2024 13:27:23 -0800 Subject: [PATCH 187/189] Remove annotations from the attribute index This is just for navigation, these aren't specific rules. --- src/attributes.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index ee38dcd..e63866e 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -240,24 +240,20 @@ r[attributes.builtin] The following is an index of all built-in attributes. -r[attributes.builtin.cfg] - Conditional compilation - [`cfg`] --- Controls conditional compilation. - [`cfg_attr`] --- Conditionally includes attributes. -r[attributes.builtin.testing] - Testing - [`test`] --- Marks a function as a test. - [`ignore`] --- Disables a test function. - [`should_panic`] --- Indicates a test should generate a panic. -r[attributes.builtin.derive] - Derive - [`derive`] --- Automatic trait implementations. - [`automatically_derived`] --- Marker for implementations created by `derive`. -r[attributes.builtin.macros] - Macros - [`macro_export`] --- Exports a `macro_rules` macro for cross-crate usage. - [`macro_use`] --- Expands macro visibility, or imports macros from other @@ -266,7 +262,6 @@ r[attributes.builtin.macros] - [`proc_macro_derive`] --- Defines a derive macro. - [`proc_macro_attribute`] --- Defines an attribute macro. -r[attributes.builtin.diagnostic] - Diagnostics - [`allow`], [`expect`], [`warn`], [`deny`], [`forbid`] --- Alters the default lint level. - [`deprecated`] --- Generates deprecation notices. @@ -274,7 +269,6 @@ r[attributes.builtin.diagnostic] - [`diagnostic::on_unimplemented`] --- Hints the compiler to emit a certain error message if a trait is not implemented. -r[attributes.builtin.linkage] - ABI, linking, symbols, and FFI - [`link`] --- Specifies a native library to link with an `extern` block. - [`link_name`] --- Specifies the name of the symbol for functions or statics @@ -294,7 +288,6 @@ r[attributes.builtin.linkage] object file. - [`crate_name`] --- Specifies the crate name. -r[attributes.builtin.codegen] - Code generation - [`inline`] --- Hint to inline code. - [`cold`] --- Hint that a function is unlikely to be called. @@ -303,43 +296,35 @@ r[attributes.builtin.codegen] - [`track_caller`] - Pass the parent call location to `std::panic::Location::caller()`. - [`instruction_set`] - Specify the instruction set used to generate a functions code -r[attributes.builtin.doc] - Documentation - `doc` --- Specifies documentation. See [The Rustdoc Book] for more information. [Doc comments] are transformed into `doc` attributes. -r[attributes.builtin.prelude] - Preludes - [`no_std`] --- Removes std from the prelude. - [`no_implicit_prelude`] --- Disables prelude lookups within a module. -r[attributes.builtin.module] - Modules - [`path`] --- Specifies the filename for a module. -r[attributes.builtin.limits] - Limits - [`recursion_limit`] --- Sets the maximum recursion limit for certain compile-time operations. - [`type_length_limit`] --- Sets the maximum size of a polymorphic type. -r[attributes.builtin.rt] - Runtime - [`panic_handler`] --- Sets the function to handle panics. - [`global_allocator`] --- Sets the global memory allocator. - [`windows_subsystem`] --- Specifies the windows subsystem to link with. -r[attributes.builtin.unstable] - Features - `feature` --- Used to enable unstable or experimental compiler features. See [The Unstable Book] for features implemented in `rustc`. -r[attributes.builtin.typesystem] - Type System - [`non_exhaustive`] --- Indicate that a type will have more fields/variants added in future. -r[attributes.builtin.debugging] - Debugger - [`debugger_visualizer`] --- Embeds a file that specifies debugger output for a type. - [`collapse_debuginfo`] --- Controls how macro invocations are encoded in debuginfo. From 2bb8df98b6c2a116cd87a7fbb7ad3d32021d6404 Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 15 Nov 2024 13:31:35 -0800 Subject: [PATCH 188/189] Change a few rule names These are some misc rule name changes. Some of them are to give the rules more specific names (indicating what they do, instead of using generic terms). The `allowed-positions` name is intended to be used for all attributes to have a specific rule that defines where an attribute may be used. It is not consistently used, yet. Also, some of the paragraphs mix "where it goes" with "what it does" that should probably be teased apart so that we can label those independently. I expect us to do some more cleanup to bring some consistency to the attribute rules since there are a lot of attributes, and they generally have the same requirements of what needs to be specified. --- src/attributes.md | 2 +- src/attributes/codegen.md | 6 +++--- src/attributes/diagnostics.md | 13 ++++++++----- src/attributes/limits.md | 2 +- src/attributes/testing.md | 4 ++-- src/attributes/type_system.md | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index e63866e..399a885 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -54,7 +54,7 @@ Attributes can be classified into the following kinds: * [Derive macro helper attributes] * [Tool attributes](#tool-attributes) -r[attributes.application] +r[attributes.allowed-position] Attributes may be applied to many things in the language: * All [item declarations] accept outer attributes while [external blocks], diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 18fa36f..3e24a32 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -80,7 +80,7 @@ Each [target architecture] has a set of features that may be enabled. It is an error to specify a feature for a target architecture that the crate is not being compiled for. -r[attributes.codegen.target_feature.precondition] +r[attributes.codegen.target_feature.target-ub] It is [undefined behavior] to call a function that is compiled with a feature that is not supported on the current platform the code is running on, *except* if the platform explicitly documents this to be safe. @@ -344,7 +344,7 @@ in the standard library for runtime feature detection on these platforms. r[attributes.codegen.track_caller] -r[attributes.codegen.track_caller.restriction] +r[attributes.codegen.track_caller.allowed-positions] The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] with the exception of the entry point `fn main`. @@ -478,7 +478,7 @@ trait object whose methods are attributed. r[attributes.codegen.instruction_set] -r[attributes.codegen.instruction_set.restriction] +r[attributes.codegen.instruction_set.allowed-positions] The *`instruction_set` [attribute]* may be applied to a function to control which instruction set the function will be generated for. r[attributes.codegen.instruction_set.behavior] diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index df7d166..8b3ad92 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -326,7 +326,7 @@ The `deprecated` attribute has several forms: message. This is typically used to provide an explanation about the deprecation and preferred alternatives. -r[attributes.diagnostic.deprecated.application] +r[attributes.diagnostic.deprecated.allowed-positions] The `deprecated` attribute may be applied to any [item], [trait item], [enum variant], [struct field], [external block item], or [macro definition]. It cannot be applied to [trait implementation items]. When applied to an item @@ -354,13 +354,16 @@ The [RFC][1270-deprecation.md] contains motivations and more details. r[attributes.diagnostic.must_use] -r[attributes.diagnostic.must_use.application] +r[attributes.diagnostic.must_use.intro] The *`must_use` attribute* is used to issue a diagnostic warning when a value -is not "used". It can be applied to user-defined composite types +is not "used". + +r[attributes.diagnostic.must_use.allowed-positions] +The `must_use` attribute can be applied to user-defined composite types ([`struct`s][struct], [`enum`s][enum], and [`union`s][union]), [functions], and [traits]. -r[attributes.diagnostic.must_use.syntax] +r[attributes.diagnostic.must_use.message] The `must_use` attribute may include a message by using the [_MetaNameValueStr_] syntax such as `#[must_use = "example message"]`. The message will be given alongside the warning. @@ -486,7 +489,7 @@ r[attributes.diagnostic.on_unimplemented] r[attributes.diagnostic.on_unimplemented.intro] The `#[diagnostic::on_unimplemented]` attribute is a hint to the compiler to supplement the error message that would normally be generated in scenarios where a trait is required but not implemented on a type. -r[attributes.diagnostic.on_unimplemented.application] +r[attributes.diagnostic.on_unimplemented.allowed-positions] The attribute should be placed on a [trait declaration], though it is not an error to be located in other positions. r[attributes.diagnostic.on_unimplemented.syntax] diff --git a/src/attributes/limits.md b/src/attributes/limits.md index 7e06cb4..1c8c46b 100644 --- a/src/attributes/limits.md +++ b/src/attributes/limits.md @@ -8,7 +8,7 @@ The following [attributes] affect compile-time limits. r[attributes.limits.recursion_limit] -r[attributes.limits.recursion_limit.application] +r[attributes.limits.recursion_limit.intro] The *`recursion_limit` attribute* may be applied at the [crate] level to set the maximum depth for potentially infinitely-recursive compile-time operations like macro expansion or auto-dereference. diff --git a/src/attributes/testing.md b/src/attributes/testing.md index 2d4ffaf..d245da6 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -17,7 +17,7 @@ The *`test` attribute* marks a function to be executed as a test. r[attributes.testing.test.enabled] These functions are only compiled when in test mode. -r[attributes.testing.test.target] +r[attributes.testing.test.allowed-positions] Test functions must be free, monomorphic functions that take no arguments, and the return type must implement the [`Termination`] trait, for example: * `()` @@ -78,7 +78,7 @@ fn mytest() { r[attributes.testing.should_panic] -r[attributes.testing.should_panic.target] +r[attributes.testing.should_panic.intro] A function annotated with the `test` attribute that returns `()` can also be annotated with the `should_panic` attribute. diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index 5325a88..e26de12 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -12,7 +12,7 @@ r[attributes.type-system.non_exhaustive.intro] The *`non_exhaustive` attribute* indicates that a type or variant may have more fields or variants added in the future. -r[attributes.type-system.non_exhaustive.application] +r[attributes.type-system.non_exhaustive.allowed-positions] It can be applied to [`struct`s][struct], [`enum`s][enum], and `enum` variants. r[attributes.type-system.non_exhaustive.syntax] From ca23373c1658f19d9d0923b70b4bdd729bd4fa7f Mon Sep 17 00:00:00 2001 From: Tiger0202 Date: Fri, 15 Nov 2024 13:42:30 -0800 Subject: [PATCH 189/189] Use plural `diagnostics` for diagnostics chapter This is keeping in line with using plurals throughout the rest of the naming convention. This also differentiates it from the `diagnostic` namespace. The `diagnostic` namespace remains singular, and is not nested with the plural `diagnostics` just to avoid the repetition. --- src/attributes/diagnostics.md | 62 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 8b3ad92..eb5caf2 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -1,18 +1,18 @@ # Diagnostic attributes -r[attributes.diagnostic] +r[attributes.diagnostics] The following [attributes] are used for controlling or generating diagnostic messages during compilation. ## Lint check attributes -r[attributes.diagnostic.lint] +r[attributes.diagnostics.lint] A lint check names a potentially undesirable coding pattern, such as unreachable code or omitted documentation. -r[attributes.diagnostic.lint.level] +r[attributes.diagnostics.lint.level] The lint attributes `allow`, `expect`, `warn`, `deny`, and `forbid` use the [_MetaListPaths_] syntax to specify a list of lint names to change the lint level for the entity @@ -20,22 +20,22 @@ to which the attribute applies. For any lint check `C`: -r[attributes.diagnostic.lint.allow] +r[attributes.diagnostics.lint.allow] * `#[allow(C)]` overrides the check for `C` so that violations will go unreported. -r[attributes.diagnostic.lint.expect] +r[attributes.diagnostics.lint.expect] * `#[expect(C)]` indicates that lint `C` is expected to be emitted. The attribute will suppress the emission of `C` or issue a warning, if the expectation is unfulfilled. -r[attributes.diagnostic.lint.warn] +r[attributes.diagnostics.lint.warn] * `#[warn(C)]` warns about violations of `C` but continues compilation. -r[attributes.diagnostic.lint.deny] +r[attributes.diagnostics.lint.deny] * `#[deny(C)]` signals an error after encountering a violation of `C`, -r[attributes.diagnostic.lint.forbid] +r[attributes.diagnostics.lint.forbid] * `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint level afterwards, @@ -58,7 +58,7 @@ pub mod m1 { } ``` -r[attributes.diagnostic.lint.override] +r[attributes.diagnostics.lint.override] Lint attributes can override the level specified from a previous attribute, as long as the level does not attempt to change a forbidden lint (except for `deny`, which is allowed inside a `forbid` context, but ignored). @@ -106,7 +106,7 @@ pub mod m3 { ### Lint Reasons -r[attributes.diagnostic.lint.reason] +r[attributes.diagnostics.lint.reason] All lint attributes support an additional `reason` parameter, to give context why a certain attribute was added. This reason will be displayed as part of the lint message if the lint is emitted at the defined level. @@ -143,9 +143,9 @@ pub fn get_path() -> PathBuf { ### The `#[expect]` attribute -r[attributes.diagnostic.expect] +r[attributes.diagnostics.expect] -r[attributes.diagnostic.expect.intro] +r[attributes.diagnostics.expect.intro] The `#[expect(C)]` attribute creates a lint expectation for lint `C`. The expectation will be fulfilled, if a `#[warn(C)]` attribute at the same location would result in a lint emission. If the expectation is unfulfilled, because @@ -171,7 +171,7 @@ fn main() { } ``` -r[attributes.lints.expect.fulfillment] +r[attributes.diagnostics.expect.fulfillment] The lint expectation is only fulfilled by lint emissions which have been suppressed by the `expect` attribute. If the lint level is modified in the scope with other level attributes like `allow` or `warn`, the lint emission will be handled accordingly and the @@ -201,7 +201,7 @@ fn select_song() { } ``` -r[attributes.diagnostic.expect.independent] +r[attributes.diagnostics.expect.independent] If the `expect` attribute contains several lints, each one is expected separately. For a lint group it's enough if one lint inside the group has been emitted: @@ -230,7 +230,7 @@ pub fn another_example() { ### Lint groups -r[attributes.diagnostic.lint.group] +r[attributes.diagnostics.lint.group] Lints may be organized into named groups so that the level of related lints can be adjusted together. Using a named group is equivalent to listing out the lints within that group. @@ -251,7 +251,7 @@ fn example() { } ``` -r[attributes.diagnostic.lint.group.warnings] +r[attributes.diagnostics.lint.group.warnings] There is a special group named "warnings" which includes all lints at the "warn" level. The "warnings" group ignores attribute order and applies to all lints that would otherwise warn within the entity. @@ -271,13 +271,13 @@ fn example_err() { ### Tool lint attributes -r[attributes.diagnostic.lint.tool] +r[attributes.diagnostics.lint.tool] -r[attributes.diagnostic.lint.tool.intro] +r[attributes.diagnostics.lint.tool.intro] Tool lints allows using scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of certain tools. -r[attributes.diagnostic.lint.tool.activation] +r[attributes.diagnostics.lint.tool.activation] Tool lints only get checked when the associated tool is active. If a lint attribute, such as `allow`, references a nonexistent tool lint, the compiler will not warn about the nonexistent lint until you use the tool. @@ -305,14 +305,14 @@ fn foo() { ## The `deprecated` attribute -r[attributes.diagnostic.deprecated] +r[attributes.diagnostics.deprecated] -r[attributes.diagnostic.deprecated.intro] +r[attributes.diagnostics.deprecated.intro] The *`deprecated` attribute* marks an item as deprecated. `rustc` will issue warnings on usage of `#[deprecated]` items. `rustdoc` will show item deprecation, including the `since` version and `note`, if available. -r[attributes.diagnostic.deprecated.syntax] +r[attributes.diagnostics.deprecated.syntax] The `deprecated` attribute has several forms: - `deprecated` --- Issues a generic message. @@ -352,23 +352,23 @@ The [RFC][1270-deprecation.md] contains motivations and more details. ## The `must_use` attribute -r[attributes.diagnostic.must_use] +r[attributes.diagnostics.must_use] -r[attributes.diagnostic.must_use.intro] +r[attributes.diagnostics.must_use.intro] The *`must_use` attribute* is used to issue a diagnostic warning when a value is not "used". -r[attributes.diagnostic.must_use.allowed-positions] +r[attributes.diagnostics.must_use.allowed-positions] The `must_use` attribute can be applied to user-defined composite types ([`struct`s][struct], [`enum`s][enum], and [`union`s][union]), [functions], and [traits]. -r[attributes.diagnostic.must_use.message] +r[attributes.diagnostics.must_use.message] The `must_use` attribute may include a message by using the [_MetaNameValueStr_] syntax such as `#[must_use = "example message"]`. The message will be given alongside the warning. -r[attributes.diagnostic.must_use.type] +r[attributes.diagnostics.must_use.type] When used on user-defined composite types, if the [expression] of an [expression statement] has that type, then the `unused_must_use` lint is violated. @@ -387,7 +387,7 @@ struct MustUse { MustUse::new(); ``` -r[attributes.diagnostic.must_use.fn] +r[attributes.diagnostics.must_use.fn] When used on a function, if the [expression] of an [expression statement] is a [call expression] to that function, then the `unused_must_use` lint is violated. @@ -400,7 +400,7 @@ fn five() -> i32 { 5i32 } five(); ``` -r[attributes.diagnostic.must_use.trait] +r[attributes.diagnostics.must_use.trait] When used on a [trait declaration], a [call expression] of an [expression statement] to a function that returns an [impl trait] or a [dyn trait] of that trait violates the `unused_must_use` lint. @@ -418,7 +418,7 @@ fn get_critical() -> impl Critical { get_critical(); ``` -r[attributes.diagnostic.must_use.trait-function] +r[attributes.diagnostics.must_use.trait-function] When used on a function in a trait declaration, then the behavior also applies when the call expression is a function from an implementation of the trait. @@ -436,7 +436,7 @@ impl Trait for i32 { 5i32.use_me(); ``` -r[attributes.diagnostic.must_use.trait-impl-function] +r[attributes.diagnostics.must_use.trait-impl-function] When used on a function in a trait implementation, the attribute does nothing. > Note: Trivial no-op expressions containing the value will not violate the