Skip to content

Commit 1ae4332

Browse files
authored
Revise guideline on function pointer identity
resolved comments from reviewers
1 parent 09c8b65 commit 1ae4332

File tree

1 file changed

+31
-18
lines changed

1 file changed

+31
-18
lines changed

src/coding-guidelines/types-and-traits.rst

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Types and Traits
6464
current.checked_add(velocity).expect("Position calculation overflowed")
6565
}
6666
67-
.. guideline:: Do Not Depend on Function Pointer Identity Across Crates
67+
.. guideline:: Do not depend on function pointer identity
6868
:id: gui_QbvIknd9qNF6
6969
:category: required
7070
:status: draft
@@ -74,40 +74,53 @@ Types and Traits
7474
:scope: system
7575
:tags: surprising-behavior
7676

77-
Do not rely on the equality or stable identity of function pointers originating from different crates or that may be inlined,
78-
duplicated, or instantiated differently across compilation units, codegen units, or optimization profiles.
77+
Do not rely on the equality or stable identity of function pointers.
7978

79+
.. exception::
80+
:id: rat_kYiIiW8R2qD3
81+
:status: draft
82+
83+
``#[no_mangle]`` functions are guaranteed to have a single instance.
84+
85+
.. rationale::
86+
:id: rat_kYiIiW8R2qD2
87+
:status: draft
88+
89+
Functions may be instantiated multiple times.
90+
They may, for example, be instantiated every time they are referenced.
91+
Only ``#[no_mangle]`` functions are guaranteed to be instantiated a single time,
92+
but can cause undefined behavior if they share a symbol with other identifiers.
93+
8094
Avoid assumptions about low-level metadata (such as symbol addresses) unless explicitly guaranteed by the Ferrocene Language Specification (FLS).
81-
Function address identity is not guaranteed by Rust and must not be treated as stable.
95+
Function address identity is not guaranteed and must not be treated as stable.
8296
Rust’s ``fn`` type is a zero-sized function item promoted to a function pointer, whose address is determined by the compiler backend.
83-
When a function resides in a different crate, or when optimizations such as inlining,
84-
link-time optimization, or codegen-unit partitioning are enabled,
97+
When a function resides in a different crate or codegen-unit partitioning is enabled,
8598
the compiler may generate multiple distinct code instances for the same function or alter the address at which it is emitted.
8699

87-
Consequently, the following operations are not reliable:
100+
Consequently, the following operations are unreliable for functions which are not ``#[no_mangle]``:
88101

89102
- Comparing function pointers for equality (``fn1 == fn2``)
90103
- Assuming a unique function address
91104
- Using function pointers as identity keys (e.g., in maps, registries, matchers)
92-
- Matching behavior based on function address
105+
- Matching behavior based on function address unless you instruct the linker to put a (#[no_mangle]) function at a specific address
93106

94107
This rule applies even when the functions are semantically identical, exported as ``pub``, or defined once in source form.
95108

96109
.. rationale::
97110
:id: rat_xcVE5Hfnbb2u
98111
:status: draft
99112

100-
Compiler optimizations may cause function pointers originating from different crates to lose stable identity.
101-
Observed behaviors include:
113+
Compiler optimizations may cause function pointers to lose stable identity, for example:
102114

103-
- Cross-crate inlining producing multiple code instantiations
104-
- Codegen-unit separation causing function emission in multiple units
105-
- Incremental builds producing variant symbol addresses
106-
- Link-time optimization merging or splitting functions unpredictably
115+
- Cross-crate inlining can produce multiple code instantiations
116+
- Codegen-unit separation can cause function emission in multiple codegen units
117+
- Identical function implementations may be automatically merged as an optimization.
118+
Functions that are equivalent based only on specific hardware semantics may be merged in the machine-specific backend.
119+
Merging may also be performed as link-time optimization.
107120

108121
This behavior has resulted in real-world issues,
109122
such as the bug reported in `rust-lang/rust#117047 <https://github.com/rust-lang/rust/issues/117047>`_,
110-
where function pointer comparisons unexpectedly failed due to cross-crate inlining.
123+
where function pointer comparisons unexpectedly failed because the function in question was instantiated multiple times.
111124

112125
Violating this rule may cause:
113126

@@ -181,14 +194,14 @@ Types and Traits
181194
:id: non_compl_ex_MkAkFxjRTijy
182195
:status: draft
183196

184-
Function pointer used as a key is not guaranteed to have stable identity, as shown in this noncompliant example:
197+
A function pointer used as a key is not guaranteed to have stable identity, as shown in this noncompliant example:
185198

186199
.. code-block:: rust
187200
188201
// crate A
189202
pub fn op_mul(x: i32) -> i32 { x * 2 }
190203
191-
// crate B
204+
// crate B
192205
use crate_a::op_mul;
193206
use std::collections::HashMap;
194207

@@ -226,7 +239,7 @@ Types and Traits
226239
pub const OP_MUL: Operation = Operation { id: 1, func: op_mul };
227240
pub const OP_ADD: Operation = Operation { id: 2, func: op_add };
228241
229-
// crate B
242+
// crate B
230243

231244
use crate_a::{Operation, OP_MUL, OP_ADD};
232245
use std::collections::HashMap;

0 commit comments

Comments
 (0)