|
| 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