-
Notifications
You must be signed in to change notification settings - Fork 517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Correct errors in the reference of extern functions definitions and declarations #652
Changes from 12 commits
8ce3484
a3b91c0
ea9d02e
5aac879
7ebfe25
3d0237b
1f023cc
ace3935
30407d2
8cee694
bca3f6c
dc93dc4
9c93133
27e30fe
c4ef0ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,9 +29,13 @@ | |
> _NamedFunctionParametersWithVariadics_ :\ | ||
> ( _NamedFunctionParam_ `,` )<sup>\*</sup> _NamedFunctionParam_ `,` `...` | ||
|
||
External blocks form the basis for Rust's foreign function interface. | ||
Declarations in an external block describe symbols in external, non-Rust | ||
libraries. | ||
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 | ||
sort of like unchecked imports. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: "sort of like" reads rather like spoken English (not something you'd find in an IEEE paper, which is the sort of style we should shoot for imo...). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't intend to take @eddyb feedback literally here, but that's the best I could come up with. These blocks declare that something exists in a particular way. If you "use" (call, access, etc.) it and it doesn't exist, or it exists in a way that's different than how you declared it: boom. If you don't actually use it, whether it exists doesn't matter, and if it doesn't, that's ok. OTOH, to me, an import is an operation that brings something into scope that exists. If it doesn't exist, then you can't import it. So I'm not sure what would be the best way to make an analogy with imports here. Maybe something like
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe with an example like this: extern "C" { fn foo(); }
fn main() {
let x = foo;
if symbol_of_foo_not_linked() {
link_symbol_of_foo();
}
unsafe { x() };
} ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I use "FFI import" to mean something different from what the Also, not sure that where the function comes from in terms of linkage is that important, compared to the fact that it likely isn't even written in Rust, hence "FFI".
gnzlbg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Two kind 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. | ||
|
||
Functions within external blocks are declared in the same way as other Rust | ||
functions, with the exception that they may not have a body and are instead | ||
|
@@ -48,6 +52,8 @@ 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 within external blocks are declared in the same way as other Rust statics, | ||
gnzlbg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
with the exception that they may not have an expression initializing their value. | ||
gnzlbg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
It is `unsafe` to access a static item declared in an extern block, whether or | ||
not it's mutable. | ||
|
||
|
@@ -85,13 +91,6 @@ There are also some platform-specific ABI strings: | |
* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's | ||
`__vectorcall` and clang's `__attribute__((vectorcall))` | ||
|
||
Finally, there are some rustc-specific ABI strings: | ||
|
||
* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics. | ||
* `extern "rust-call"` -- The ABI of the Fn::call trait functions. | ||
* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for | ||
example, `sqrt` -- have this ABI. You should never have to deal with it. | ||
|
||
## Variadic functions | ||
|
||
Functions within external blocks may be variadic by specifying `...` after one | ||
|
@@ -165,6 +164,8 @@ extern { | |
|
||
[IDENTIFIER]: ../identifiers.md | ||
[WebAssembly module]: https://webassembly.github.io/spec/core/syntax/modules.html | ||
[functions]: functions.md | ||
[statics]: static-items.md | ||
[_Abi_]: functions.md | ||
[_FunctionReturnType_]: functions.md | ||
[_Generics_]: generics.md | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,35 +107,73 @@ component after the function name. This might be necessary if there is not | |
sufficient context to determine the type parameters. For example, | ||
`mem::size_of::<u32>() == 4`. | ||
|
||
## Extern functions | ||
## Extern function qualifier | ||
|
||
Extern functions are part of Rust's foreign function interface, providing the | ||
opposite functionality to [external blocks]. Whereas external | ||
blocks allow Rust code to call foreign code, extern functions with bodies | ||
defined in Rust code _can be called by foreign code_. They are defined in the | ||
same way as any other Rust function, except that they have the `extern` | ||
qualifier. | ||
The `extern` function qualifier allows providing function _definitions_ that can | ||
be called with a particular ABI: | ||
gnzlbg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```rust,ignore | ||
extern "ABI" fn foo() { ... } | ||
gnzlbg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
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_: | ||
|
||
```rust,ignore | ||
extern "ABI" { | ||
fn foo(); /* no body */ | ||
} | ||
unsafe { foo() } | ||
``` | ||
|
||
When `"extern" Abi?*` is omitted from `FunctionQualifiers` in function items, | ||
the ABI `"Rust"` is assigned. For example: | ||
|
||
```rust | ||
// Declares an extern fn, the ABI defaults to "C" | ||
extern fn new_i32() -> i32 { 0 } | ||
fn foo() {} | ||
``` | ||
|
||
is equivalent to: | ||
|
||
// Declares an extern fn with "stdcall" ABI | ||
```rust | ||
extern "Rust" fn foo() {} | ||
``` | ||
|
||
Functions in Rust can be called by foreign code, and using an ABI that | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a run-on sentence, or at least feels like one. Also, "Rust's functions". And what does "foreign code" here mean differently than code from other programming languages? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rust code exposed with a C ABI. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how to improve this. |
||
differs from Rust allows, for example, to provide functions that can be | ||
called from other programming languages like C: | ||
|
||
```rust | ||
// Declares a function with the "C" ABI | ||
extern "C" fn new_i32() -> i32 { 0 } | ||
|
||
// Declares a function with the "stdcall" ABI | ||
# #[cfg(target_arch = "x86_64")] | ||
extern "stdcall" fn new_i32_stdcall() -> i32 { 0 } | ||
``` | ||
|
||
Unlike normal functions, extern fns have type `extern "ABI" fn()`. This is the | ||
same type as the functions declared in an extern block. | ||
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: | ||
|
||
```rust | ||
# extern fn new_i32() -> i32 { 0 } | ||
extern fn new_i32() -> i32 { 0 } | ||
let fptr: extern fn() -> i32 = new_i32; | ||
``` | ||
|
||
is equivalent to: | ||
|
||
```rust | ||
extern "C" fn new_i32() -> i32 { 0 } | ||
let fptr: extern "C" fn() -> i32 = new_i32; | ||
``` | ||
|
||
As non-Rust calling conventions do not support unwinding, unwinding past the end | ||
of an extern function will cause the process to abort. In LLVM, this is | ||
implemented by executing an illegal instruction. | ||
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. | ||
|
||
> **Note**: The LLVM backend of the `rustc` implementation | ||
aborts the process by executing an illegal instruction. | ||
|
||
## Const functions | ||
|
||
|
@@ -243,3 +281,4 @@ attributes macros. | |
[`export_name`]: ../abi.md#the-export_name-attribute | ||
[`link_section`]: ../abi.md#the-link_section-attribute | ||
[`no_mangle`]: ../abi.md#the-no_mangle-attribute | ||
[external_block_abi]: external-blocks.md#abi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be more explicit that these are "imports" of a sort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried to clarify that.