From d4b5620047b7de28c84ab8c4373cbc9f45bf54db Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 18 Jul 2024 13:05:50 -0300 Subject: [PATCH 1/9] 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 9abce3fd4..937cd92e3 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 ae698fba2..4e00cacd8 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 3fbd2ad5c..8ed2248d9 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 2d83af6a785893551d6fbe6235f1ffe66bea9eca Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 21 Jul 2024 08:55:51 +0000 Subject: [PATCH 2/9] 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 937cd92e3..85fe22b4e 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 4e00cacd8..77d9510c8 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 8ed2248d9..7f58a3ace 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 d1a75641d42e6b140cae4b224827d4f08fea53a2 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sun, 21 Jul 2024 09:54:22 +0000 Subject: [PATCH 3/9] 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 85fe22b4e..ba3626306 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 77d9510c8..8650292ca 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 2f5e96b6406b7ed2fe150d971f64cda6a094e6f0 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 22 Jul 2024 08:29:49 +0000 Subject: [PATCH 4/9] 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 a29fc9432..63bc13879 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 915fa5b03..2330edd48 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 00540f1de0d49531fae10637dfdce1ddda846a38 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 23 Jul 2024 13:56:30 -0700 Subject: [PATCH 5/9] 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 46da9f1e2..c6472a37b 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 66e12f1c531e6ef6f7e4b86c0803de8c6339d033 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 23 Jul 2024 14:01:17 -0700 Subject: [PATCH 6/9] 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 ba3626306..d65e9244b 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 1072b01d42d5eb7503cfa90e2a5d0bc2ee64d5ba Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 24 Jul 2024 16:42:09 -0700 Subject: [PATCH 7/9] 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 d65e9244b..6f7d883d6 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 8650292ca..af4fc7bc7 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 343d30cbe..f00f1aab8 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 a1a6f294fa6496245505a0e30ca8d95b45a18aef Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 24 Jul 2024 16:43:18 -0700 Subject: [PATCH 8/9] 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 6f7d883d6..3af2a67f0 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 875b905a389455c5329ae088600c0b5f7222104d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 9 Aug 2024 15:30:05 -0700 Subject: [PATCH 9/9] 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 3af2a67f0..bb59af898 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 af4fc7bc7..54988df31 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 63bc13879..df68a74cc 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 2330edd48..237a4bfec 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