forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#71718 - NeoRaider:ffi_const_pure, r=Amanieu
Experimentally add `ffi_const` and `ffi_pure` extern fn attributes Add FFI function attributes corresponding to clang/gcc/... `const` and `pure`. Rebased version of rust-lang#58327 by @gnzlbg with the following changes: - Switched back from the `c_ffi_const` and `c_ffi_pure` naming to `ffi_const` and `ffi_pure`, as I agree with rust-lang#58327 (comment) and this nicely aligns with `ffi_returns_twice` - (Hopefully) took care of all of @hanna-kruppe's change requests in the original PR r? @hanna-kruppe
- Loading branch information
Showing
21 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# `ffi_const` | ||
|
||
The `#[ffi_const]` attribute applies clang's `const` attribute to foreign | ||
functions declarations. | ||
|
||
That is, `#[ffi_const]` functions shall have no effects except for its return | ||
value, which can only depend on the values of the function parameters, and is | ||
not affected by changes to the observable state of the program. | ||
|
||
Applying the `#[ffi_const]` attribute to a function that violates these | ||
requirements is undefined behaviour. | ||
|
||
This attribute enables Rust to perform common optimizations, like sub-expression | ||
elimination, and it can avoid emitting some calls in repeated invocations of the | ||
function with the same argument values regardless of other operations being | ||
performed in between these functions calls (as opposed to `#[ffi_pure]` | ||
functions). | ||
|
||
## Pitfalls | ||
|
||
A `#[ffi_const]` function can only read global memory that would not affect | ||
its return value for the whole execution of the program (e.g. immutable global | ||
memory). `#[ffi_const]` functions are referentially-transparent and therefore | ||
more strict than `#[ffi_pure]` functions. | ||
|
||
A common pitfall involves applying the `#[ffi_const]` attribute to a | ||
function that reads memory through pointer arguments which do not necessarily | ||
point to immutable global memory. | ||
|
||
A `#[ffi_const]` function that returns unit has no effect on the abstract | ||
machine's state, and a `#[ffi_const]` function cannot be `#[ffi_pure]`. | ||
|
||
A `#[ffi_const]` function must not diverge, neither via a side effect (e.g. a | ||
call to `abort`) nor by infinite loops. | ||
|
||
When translating C headers to Rust FFI, it is worth verifying for which targets | ||
the `const` attribute is enabled in those headers, and using the appropriate | ||
`cfg` macros in the Rust side to match those definitions. While the semantics of | ||
`const` are implemented identically by many C and C++ compilers, e.g., clang, | ||
[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily | ||
implemented in this way on all of them. It is therefore also worth verifying | ||
that the semantics of the C toolchain used to compile the binary being linked | ||
against are compatible with those of the `#[ffi_const]`. | ||
|
||
[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html | ||
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute | ||
[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# `ffi_pure` | ||
|
||
The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign | ||
functions declarations. | ||
|
||
That is, `#[ffi_pure]` functions shall have no effects except for its return | ||
value, which shall not change across two consecutive function calls with | ||
the same parameters. | ||
|
||
Applying the `#[ffi_pure]` attribute to a function that violates these | ||
requirements is undefined behavior. | ||
|
||
This attribute enables Rust to perform common optimizations, like sub-expression | ||
elimination and loop optimizations. Some common examples of pure functions are | ||
`strlen` or `memcmp`. | ||
|
||
These optimizations are only applicable when the compiler can prove that no | ||
program state observable by the `#[ffi_pure]` function has changed between calls | ||
of the function, which could alter the result. See also the `#[ffi_const]` | ||
attribute, which provides stronger guarantees regarding the allowable behavior | ||
of a function, enabling further optimization. | ||
|
||
## Pitfalls | ||
|
||
A `#[ffi_pure]` function can read global memory through the function | ||
parameters (e.g. pointers), globals, etc. `#[ffi_pure]` functions are not | ||
referentially-transparent, and are therefore more relaxed than `#[ffi_const]` | ||
functions. | ||
|
||
However, accesing global memory through volatile or atomic reads can violate the | ||
requirement that two consecutive function calls shall return the same value. | ||
|
||
A `pure` function that returns unit has no effect on the abstract machine's | ||
state. | ||
|
||
A `#[ffi_pure]` function must not diverge, neither via a side effect (e.g. a | ||
call to `abort`) nor by infinite loops. | ||
|
||
When translating C headers to Rust FFI, it is worth verifying for which targets | ||
the `pure` attribute is enabled in those headers, and using the appropriate | ||
`cfg` macros in the Rust side to match those definitions. While the semantics of | ||
`pure` are implemented identically by many C and C++ compilers, e.g., clang, | ||
[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily | ||
implemented in this way on all of them. It is therefore also worth verifying | ||
that the semantics of the C toolchain used to compile the binary being linked | ||
against are compatible with those of the `#[ffi_pure]`. | ||
|
||
|
||
[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html | ||
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute | ||
[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// compile-flags: -C no-prepopulate-passes | ||
#![crate_type = "lib"] | ||
#![feature(ffi_const)] | ||
|
||
pub fn bar() { unsafe { foo() } } | ||
|
||
extern { | ||
// CHECK-LABEL: declare void @foo() | ||
// CHECK-SAME: [[ATTRS:#[0-9]+]] | ||
// CHECK-DAG: attributes [[ATTRS]] = { {{.*}}readnone{{.*}} } | ||
#[ffi_const] pub fn foo(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// compile-flags: -C no-prepopulate-passes | ||
#![crate_type = "lib"] | ||
#![feature(ffi_pure)] | ||
|
||
pub fn bar() { unsafe { foo() } } | ||
|
||
extern { | ||
// CHECK-LABEL: declare void @foo() | ||
// CHECK-SAME: [[ATTRS:#[0-9]+]] | ||
// CHECK-DAG: attributes [[ATTRS]] = { {{.*}}readonly{{.*}} } | ||
#[ffi_pure] pub fn foo(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#![crate_type = "lib"] | ||
|
||
extern { | ||
#[ffi_const] //~ ERROR the `#[ffi_const]` attribute is an experimental feature | ||
pub fn foo(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
error[E0658]: the `#[ffi_const]` attribute is an experimental feature | ||
--> $DIR/feature-gate-ffi_const.rs:4:5 | ||
| | ||
LL | #[ffi_const] | ||
| ^^^^^^^^^^^^ | ||
| | ||
= note: see issue #58328 <https://github.com/rust-lang/rust/issues/58328> for more information | ||
= help: add `#![feature(ffi_const)]` to the crate attributes to enable | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0658`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#![crate_type = "lib"] | ||
|
||
extern { | ||
#[ffi_pure] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature | ||
pub fn foo(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
error[E0658]: the `#[ffi_pure]` attribute is an experimental feature | ||
--> $DIR/feature-gate-ffi_pure.rs:4:5 | ||
| | ||
LL | #[ffi_pure] | ||
| ^^^^^^^^^^^ | ||
| | ||
= note: see issue #58329 <https://github.com/rust-lang/rust/issues/58329> for more information | ||
= help: add `#![feature(ffi_pure)]` to the crate attributes to enable | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0658`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#![feature(ffi_const)] | ||
#![crate_type = "lib"] | ||
|
||
#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions | ||
pub fn foo() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
error[E0756]: `#[ffi_const]` may only be used on foreign functions | ||
--> $DIR/ffi_const.rs:4:1 | ||
| | ||
LL | #[ffi_const] | ||
| ^^^^^^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#![feature(ffi_const, ffi_pure)] | ||
|
||
extern { | ||
#[ffi_pure] //~ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]` | ||
#[ffi_const] | ||
pub fn baz(); | ||
} | ||
|
||
fn main() { | ||
unsafe { baz() }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
error[E0757]: `#[ffi_const]` function cannot be `#[ffi_pure]` | ||
--> $DIR/ffi_const2.rs:4:5 | ||
| | ||
LL | #[ffi_pure] | ||
| ^^^^^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#![feature(ffi_pure)] | ||
#![crate_type = "lib"] | ||
|
||
#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions | ||
pub fn foo() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
error[E0755]: `#[ffi_pure]` may only be used on foreign functions | ||
--> $DIR/ffi_pure.rs:4:1 | ||
| | ||
LL | #[ffi_pure] | ||
| ^^^^^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|