Skip to content

Commit a114a23

Browse files
committed
Document #[ffi_const] and #[ffi_pure] function attributes in unstable book
Based on the work of gnzlbg <[email protected]>.
1 parent a7d7f0b commit a114a23

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# `ffi_const`
2+
3+
The `#[ffi_const]` attribute applies clang's `const` attribute to foreign
4+
functions declarations.
5+
6+
That is, `#[ffi_const]` functions shall have no effects except for its return
7+
value, which can only depend on the values of the function parameters, and is
8+
not affected by changes to the observable state of the program.
9+
10+
Applying the `#[ffi_const]` attribute to a function that violates these
11+
requirements is undefined behaviour.
12+
13+
This attribute enables Rust to perform common optimizations, like sub-expression
14+
elimination, and it can avoid emitting some calls in repeated invocations of the
15+
function with the same argument values regardless of other operations being
16+
performed in between these functions calls (as opposed to `#[ffi_pure]`
17+
functions).
18+
19+
## Pitfalls
20+
21+
A `#[ffi_const]` function can only read global memory that would not affect
22+
its return value for the whole execution of the program (e.g. immutable global
23+
memory). `#[ffi_const]` functions are referentially-transparent and therefore
24+
more strict than `#[ffi_pure]` functions.
25+
26+
A common pitfall involves applying the `#[ffi_const]` attribute to a
27+
function that reads memory through pointer arguments which do not necessarily
28+
point to immutable global memory.
29+
30+
A `#[ffi_const]` function that returns unit has no effect on the abstract
31+
machine's state, and a `#[ffi_const]` function cannot be `#[ffi_pure]`.
32+
33+
A `#[ffi_const]` function must not diverge, neither via a side effect (e.g. a
34+
call to `abort`) nor by infinite loops.
35+
36+
When translating C headers to Rust FFI, it is worth verifying for which targets
37+
the `const` attribute is enabled in those headers, and using the appropriate
38+
`cfg` macros in the Rust side to match those definitions. While the semantics of
39+
`const` are implemented identically by many C and C++ compilers, e.g., clang,
40+
[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily
41+
implemented in this way on all of them. It is therefore also worth verifying
42+
that the semantics of the C toolchain used to compile the binary being linked
43+
against are compatible with those of the `#[ffi_const]`.
44+
45+
[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html
46+
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute
47+
[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# `ffi_pure`
2+
3+
The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign
4+
functions declarations.
5+
6+
That is, `#[ffi_pure]` functions shall have no effects except for its return
7+
value, which shall not change across two consecutive function calls with
8+
the same parameters.
9+
10+
Applying the `#[ffi_pure]` attribute to a function that violates these
11+
requirements is undefined behavior.
12+
13+
This attribute enables Rust to perform common optimizations, like sub-expression
14+
elimination and loop optimizations. Some common examples of pure functions are
15+
`strlen` or `memcmp`.
16+
17+
These optimizations are only applicable when the compiler can prove that no
18+
program state observable by the `#[ffi_pure]` function has changed between calls
19+
of the function, which could alter the result. See also the `#[ffi_const]`
20+
attribute, which provides stronger guarantees regarding the allowable behavior
21+
of a function, enabling further optimization.
22+
23+
## Pitfalls
24+
25+
A `#[ffi_pure]` function can read global memory through the function
26+
parameters (e.g. pointers), globals, etc. `#[ffi_pure]` functions are not
27+
referentially-transparent, and are therefore more relaxed than `#[ffi_const]`
28+
functions.
29+
30+
However, accesing global memory through volatile or atomic reads can violate the
31+
requirement that two consecutive function calls shall return the same value.
32+
33+
A `pure` function that returns unit has no effect on the abstract machine's
34+
state.
35+
36+
A `#[ffi_pure]` function must not diverge, neither via a side effect (e.g. a
37+
call to `abort`) nor by infinite loops.
38+
39+
When translating C headers to Rust FFI, it is worth verifying for which targets
40+
the `pure` attribute is enabled in those headers, and using the appropriate
41+
`cfg` macros in the Rust side to match those definitions. While the semantics of
42+
`pure` are implemented identically by many C and C++ compilers, e.g., clang,
43+
[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily
44+
implemented in this way on all of them. It is therefore also worth verifying
45+
that the semantics of the C toolchain used to compile the binary being linked
46+
against are compatible with those of the `#[ffi_pure]`.
47+
48+
49+
[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html
50+
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute
51+
[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm

0 commit comments

Comments
 (0)