diff --git a/src/abi.md b/src/abi.md index f244ead5d..2e9e969ac 100644 --- a/src/abi.md +++ b/src/abi.md @@ -88,7 +88,7 @@ pub fn name_in_rust() { } [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax [`static` items]: items/static-items.md [attribute]: attributes.md -[extern functions]: items/functions.md#extern-functions +[extern functions]: items/functions.md#extern-function-qualifier [external blocks]: items/external-blocks.md [function]: items/functions.md [item]: items.md diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index 9c69ad0ed..f3e692ac9 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -29,9 +29,13 @@ > _NamedFunctionParametersWithVariadics_ :\ >    ( _NamedFunctionParam_ `,` )\* _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 +akin to unchecked imports. + +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 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. @@ -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 diff --git a/src/items/functions.md b/src/items/functions.md index bae5b8eff..7c93dc423 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -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::() == 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: + +```rust,ignore +extern "ABI" fn foo() { ... } +``` + +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 +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 diff --git a/src/types/function-pointer.md b/src/types/function-pointer.md index 44da3ccbd..88ef50c24 100644 --- a/src/types/function-pointer.md +++ b/src/types/function-pointer.md @@ -51,6 +51,6 @@ x = bo(5,7); [_Type_]: ../types.md#type-expressions [`extern`]: ../items/external-blocks.md [closures]: closure.md -[extern function]: ../items/functions.md#extern-functions +[extern function]: ../items/functions.md#extern-function-qualifier [function items]: function-item.md [unsafe function]: ../unsafe-functions.md