Skip to content

Commit 7226782

Browse files
authored
Merge pull request #1536 from spastorino/unsafe-extern-blocks
Changes for unsafe extern blocks (RFC 3484)
2 parents 539f44a + 875b905 commit 7226782

File tree

7 files changed

+71
-46
lines changed

7 files changed

+71
-46
lines changed

src/items/external-blocks.md

+35-37
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,32 @@ blocks is only allowed in an `unsafe` context.
2323

2424
The external block defines its functions and statics in the [value namespace] of the module or block where it is located.
2525

26-
The `unsafe` keyword is syntactically allowed to appear before the `extern`
27-
keyword, but it is rejected at a semantic level. This allows macros to consume
28-
the syntax and make use of the `unsafe` keyword, before removing it from the
29-
token stream.
30-
3126
## Functions
3227

3328
Functions within external blocks are declared in the same way as other Rust
3429
functions, with the exception that they must not have a body and are instead
3530
terminated by a semicolon. Patterns are not allowed in parameters, only
36-
[IDENTIFIER] or `_` may be used. Function qualifiers (`const`, `async`,
37-
`unsafe`, and `extern`) are not allowed.
31+
[IDENTIFIER] or `_` may be used. The `safe` and `unsafe` function qualifiers are
32+
allowed, but other function qualifiers (e.g. `const`, `async`, `extern`) are
33+
not.
3834

3935
Functions within external blocks may be called by Rust code, just like
4036
functions defined in Rust. The Rust compiler automatically translates between
4137
the Rust ABI and the foreign ABI.
4238

43-
A function declared in an extern block is implicitly `unsafe`. When coerced to
44-
a function pointer, a function declared in an extern block has type `unsafe
45-
extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R`, where `'l1`, ... `'lm`
46-
are its lifetime parameters, `A1`, ..., `An` are the declared types of its
47-
parameters and `R` is the declared return type.
39+
A function declared in an extern block is implicitly `unsafe` unless the `safe`
40+
function qualifier is present.
41+
42+
When coerced to a function pointer, a function declared in an extern block has
43+
type `extern "abi" for<'l1, ..., 'lm> fn(A1, ..., An) -> R`, where `'l1`,
44+
... `'lm` are its lifetime parameters, `A1`, ..., `An` are the declared types of
45+
its parameters, `R` is the declared return type.
4846

4947
## Statics
5048

5149
Statics within external blocks are declared in the same way as [statics] outside of external blocks,
5250
except that they do not have an expression initializing their value.
53-
It is `unsafe` to access a static item declared in an extern block, whether or
51+
Unless a static item declared in an extern block is qualified as `safe`, it is `unsafe` to access that item, whether or
5452
not it's mutable, because there is nothing guaranteeing that the bit pattern at the static's
5553
memory is valid for the type it is declared with, since some arbitrary (e.g. C) code is in charge
5654
of initializing the static.
@@ -69,34 +67,34 @@ standard C ABI on the specific platform. Other ABIs may be specified using an
6967

7068
```rust
7169
// Interface to the Windows API
72-
extern "stdcall" { }
70+
unsafe extern "stdcall" { }
7371
```
7472

7573
There are three ABI strings which are cross-platform, and which all compilers
7674
are guaranteed to support:
7775

78-
* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any
76+
* `unsafe extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any
7977
Rust code.
80-
* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default
78+
* `unsafe extern "C"` -- This is the same as `extern fn foo()`; whatever the default
8179
your C compiler supports.
82-
* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in
80+
* `unsafe extern "system"` -- Usually the same as `extern "C"`, except on Win32, in
8381
which case it's `"stdcall"`, or what you should use to link to the Windows
8482
API itself
8583

8684
There are also some platform-specific ABI strings:
8785

88-
* `extern "cdecl"` -- The default for x86\_32 C code.
89-
* `extern "stdcall"` -- The default for the Win32 API on x86\_32.
90-
* `extern "win64"` -- The default for C code on x86\_64 Windows.
91-
* `extern "sysv64"` -- The default for C code on non-Windows x86\_64.
92-
* `extern "aapcs"` -- The default for ARM.
93-
* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
86+
* `unsafe extern "cdecl"` -- The default for x86\_32 C code.
87+
* `unsafe extern "stdcall"` -- The default for the Win32 API on x86\_32.
88+
* `unsafe extern "win64"` -- The default for C code on x86\_64 Windows.
89+
* `unsafe extern "sysv64"` -- The default for C code on non-Windows x86\_64.
90+
* `unsafe extern "aapcs"` -- The default for ARM.
91+
* `unsafe extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
9492
`__fastcall` and GCC and clang's `__attribute__((fastcall))`
95-
* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's
93+
* `unsafe extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's
9694
`__vectorcall` and clang's `__attribute__((vectorcall))`
97-
* `extern "thiscall"` -- The default for C++ member functions on MSVC -- corresponds to MSVC's
95+
* `unsafe extern "thiscall"` -- The default for C++ member functions on MSVC -- corresponds to MSVC's
9896
`__thiscall` and GCC and clang's `__attribute__((thiscall))`
99-
* `extern "efiapi"` -- The ABI used for [UEFI] functions.
97+
* `unsafe extern "efiapi"` -- The ABI used for [UEFI] functions.
10098

10199
## Variadic functions
102100

@@ -105,10 +103,10 @@ last argument. The variadic parameter may optionally be specified with an
105103
identifier.
106104

107105
```rust
108-
extern "C" {
109-
fn foo(...);
110-
fn bar(x: i32, ...);
111-
fn with_name(format: *const u8, args: ...);
106+
unsafe extern "C" {
107+
safe fn foo(...);
108+
unsafe fn bar(x: i32, ...);
109+
unsafe fn with_name(format: *const u8, args: ...);
112110
}
113111
```
114112

@@ -152,17 +150,17 @@ not specified.
152150
<!-- ignore: requires extern linking -->
153151
```rust,ignore
154152
#[link(name = "crypto")]
155-
extern {
153+
unsafe extern {
156154
// …
157155
}
158156
159157
#[link(name = "CoreFoundation", kind = "framework")]
160-
extern {
158+
unsafe extern {
161159
// …
162160
}
163161
164162
#[link(wasm_import_module = "foo")]
165-
extern {
163+
unsafe extern {
166164
// …
167165
}
168166
```
@@ -277,9 +275,9 @@ block to indicate the symbol to import for the given function or static. It
277275
uses the [_MetaNameValueStr_] syntax to specify the name of the symbol.
278276

279277
```rust
280-
extern {
278+
unsafe extern {
281279
#[link_name = "actual_symbol_name"]
282-
fn name_in_rust();
280+
safe fn name_in_rust();
283281
}
284282
```
285283

@@ -306,9 +304,9 @@ it, and that assigned ordinal may change between builds of the binary.
306304
<!-- ignore: Only works on x86 Windows -->
307305
```rust,ignore
308306
#[link(name = "exporter", kind = "raw-dylib")]
309-
extern "stdcall" {
307+
unsafe extern "stdcall" {
310308
#[link_ordinal(15)]
311-
fn imported_function_stdcall(i: i32);
309+
safe fn imported_function_stdcall(i: i32);
312310
}
313311
```
314312

src/items/functions.md

+15-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
> &nbsp;&nbsp; &nbsp;&nbsp; ( [_BlockExpression_] | `;` )
99
>
1010
> _FunctionQualifiers_ :\
11-
> &nbsp;&nbsp; `const`<sup>?</sup> `async`[^async-edition]<sup>?</sup> `unsafe`<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
11+
> &nbsp;&nbsp; `const`<sup>?</sup> `async`[^async-edition]<sup>?</sup> _ItemSafety_<sup>?</sup> (`extern` _Abi_<sup>?</sup>)<sup>?</sup>
12+
>
13+
> _ItemSafety_ :\
14+
> &nbsp;&nbsp; `safe`[^extern-safe] | `unsafe`
1215
>
1316
> _Abi_ :\
1417
> &nbsp;&nbsp; [STRING_LITERAL] | [RAW_STRING_LITERAL]
@@ -39,6 +42,9 @@
3942
>
4043
> [^async-edition]: The `async` qualifier is not allowed in the 2015 edition.
4144
>
45+
> [^extern-safe]: The `safe` function qualifier is only allowed semantically within
46+
> `extern` blocks.
47+
>
4248
> [^fn-param-2015]: Function parameters with only a type are only allowed
4349
> in an associated function of a [trait item] in the 2015 edition.
4450
@@ -58,6 +64,8 @@ fn answer_to_life_the_universe_and_everything() -> i32 {
5864
}
5965
```
6066

67+
The `safe` function is semantically only allowed when used in an [`extern` block].
68+
6169
## Function parameters
6270

6371
Function parameters are irrefutable [patterns], so any pattern that is valid in
@@ -157,10 +165,12 @@ their _definition_:
157165

158166
<!-- ignore: fake ABI -->
159167
```rust,ignore
160-
extern "ABI" {
161-
fn foo(); /* no body */
168+
unsafe extern "ABI" {
169+
unsafe fn foo(); /* no body */
170+
safe fn bar(); /* no body */
162171
}
163-
unsafe { foo() }
172+
unsafe { foo() };
173+
bar();
164174
```
165175

166176
When `"extern" Abi?*` is omitted from `FunctionQualifiers` in function items,
@@ -415,3 +425,4 @@ fn foo_oof(#[some_inert_attribute] arg: u8) {
415425
[implementation]: implementations.md
416426
[value namespace]: ../names/namespaces.md
417427
[variadic function]: external-blocks.md#variadic-functions
428+
[`extern` block]: external-blocks.md

src/items/static-items.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
> **<sup>Syntax</sup>**\
44
> _StaticItem_ :\
5-
> &nbsp;&nbsp; `static` `mut`<sup>?</sup> [IDENTIFIER] `:` [_Type_]
5+
> &nbsp;&nbsp; [_ItemSafety_]<sup>?</sup>[^extern-safety] `static` `mut`<sup>?</sup> [IDENTIFIER] `:` [_Type_]
66
> ( `=` [_Expression_] )<sup>?</sup> `;`
7+
>
8+
> [^extern-safety]: The `safe` and `unsafe` function qualifiers are only
9+
> allowed semantically within `extern` blocks.
710
811
A *static item* is similar to a [constant], except that it represents a precise
912
memory location in the program. All references to the static refer to the same
@@ -28,6 +31,8 @@ statics:
2831
The initializer expression must be omitted in an [external block], and must be
2932
provided for free static items.
3033

34+
The `safe` and `unsafe` qualifiers are semantically only allowed when used in an [external block].
35+
3136
## Statics & generics
3237

3338
A static item defined in a generic scope (for example in a blanket or default
@@ -139,3 +144,4 @@ following are true:
139144
[_Type_]: ../types.md#type-expressions
140145
[_Expression_]: ../expressions.md
141146
[value namespace]: ../names/namespaces.md
147+
[_ItemSafety_]: functions.md

src/keywords.md

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ is possible to declare a variable or method with the name `union`.
118118
>
119119
> **<sup>Lexer 2015</sup>**\
120120
> KW_DYN : `dyn`
121+
* `safe` is used for functions and statics, which has meaning in [external blocks].
121122

122123
[items]: items.md
123124
[Variables]: variables.md
@@ -132,3 +133,4 @@ is possible to declare a variable or method with the name `union`.
132133
[`dyn`]: types/trait-object.md
133134
[loop label]: expressions/loop-expr.md#loop-labels
134135
[generic lifetime parameter]: items/generics.md
136+
[external blocks]: items/external-blocks.md

src/types/never.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn foo() -> ! {
1717
```
1818

1919
```rust
20-
extern "C" {
21-
pub fn no_return_extern_func() -> !;
20+
unsafe extern "C" {
21+
pub safe fn no_return_extern_func() -> !;
2222
}
2323
```

src/unsafe-keyword.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# The `unsafe` keyword
22

33
The `unsafe` keyword can occur in several different contexts:
4-
unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), and unsafe trait implementations (`unsafe impl`).
4+
unsafe functions (`unsafe fn`), unsafe blocks (`unsafe {}`), unsafe traits (`unsafe trait`), unsafe trait implementations (`unsafe impl`), and unsafe external blocks (`unsafe extern`).
55
It plays several different roles, depending on where it is used and whether the `unsafe_op_in_unsafe_fn` lint is enabled:
66
- it is used to mark code that *defines* extra safety conditions (`unsafe fn`, `unsafe trait`)
7-
- it is used to mark code that needs to *satisfy* extra safety conditions (`unsafe {}`, `unsafe impl`, `unsafe fn` without [`unsafe_op_in_unsafe_fn`])
7+
- 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`)
88

99
The following discusses each of these cases.
1010
See the [keyword documentation][keyword] for some illustrative examples.
@@ -56,3 +56,9 @@ Unsafe trait implementations are the logical dual to unsafe traits: where unsafe
5656
[keyword]: ../std/keyword.unsafe.html
5757
[`get_unchecked`]: ../std/primitive.slice.html#method.get_unchecked
5858
[`unsafe_op_in_unsafe_fn`]: ../rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn
59+
60+
## Unsafe external blocks (`unsafe extern`)
61+
62+
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`.
63+
64+
[external block]: items/external-blocks.md

src/unsafety.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ Rust:
1111
- Accessing a field of a [`union`], other than to assign to it.
1212
- Calling an unsafe function (including an intrinsic or foreign function).
1313
- Implementing an [unsafe trait].
14+
- Declaring an [`extern`] block.
1415

16+
[`extern`]: items/external-blocks.md
1517
[`union`]: items/unions.md
1618
[mutable]: items/static-items.md#mutable-statics
1719
[external]: items/external-blocks.md

0 commit comments

Comments
 (0)