You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/0000-float-semantics.md
+10-1Lines changed: 10 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -90,7 +90,7 @@ Unless noted otherwise, the same rules also apply to NaNs returned by other libr
90
90
91
91
### `const` semantics
92
92
93
-
Const-evaluation must necessarily be deterministic to ensure soundness of the type system.
93
+
Evaluation of `const` items (and other entry points to CTFE) must necessarily be deterministic to ensure soundness of the type system.
94
94
`const` use of floating points does not make any guarantees beyond that:
95
95
when a floating-point operation produces a NaN result, the resulting NaN bit pattern is *some* deterministic function of the operation's inputs that satisfies the constraints placed on run-time floating point semantics.
96
96
However, the exact function is not specified, and it is allowed to change across targets and Rust versions, and even with compiler flags.
@@ -126,6 +126,9 @@ assert_eq!(C, div(0.0));
126
126
The first assertion is very unlikely to fail in practice (it would require the two invocations of `div` to be optimized differently).
127
127
The second however [actually fails](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=0b4b952929c9ebcd2bd50aee54e6cdf4) on current nightlies in debug mode.
128
128
129
+
Even running the same expression (such as `0.0 / 0.0`) twice as part of evaluating a given `const` item, or in two different `const` items, may produce different results.
130
+
The only guarantee the type system needs is that evaluating `some_crate::SOME_CONST` will produce consistent results if evaluation is repeated in different compilation units, and so that is all we guarantee.
131
+
129
132
This resolves the last open question blocking floating-point operations in `const fn`.
130
133
When the RFC is accepted, the `const_fn_floating_point_arithmetic` feature gate and the `const fn to_bits` methods can be stabilized.
131
134
@@ -151,6 +154,9 @@ Furthermore, observing the floating-point exception state yields entirely unspec
151
154
There is little we can do here with the current state of LLVM; and even once LLVM provides the necessary features, these signal handlers will need annotations in the code that tell the compiler about the non-default floating point state.
152
155
Those targets chose to use a semantics that is hard to support well in a highly optimized language, and there's not much we can do to paper over such target quirks.
153
156
We can only hope that eventually those targets will decide to provide a reliable floating-point environment.
157
+
Meanwhile, the best work-around is to use inline assembly to change the floating-point environment to the state that rustc expects it to be in.
158
+
While strictly speaking that would have to happen before any Rust function gets called, practically speaking if this is the first thing the signal handler does, it is very unlikely to cause a problem:
159
+
that would require the compiler to put a floating-point operation between the function start and the inline assembly block.
154
160
155
161
### Target-specific problems
156
162
@@ -243,6 +249,7 @@ Even under this alternative we would allow `const fn` to perform operations that
243
249
244
250
The core advantage of this option is that it avoids having `const` results change when the unspecified compile-time NaN changes on a compiler update or across compilers.
245
251
However, having `const` results depend on NaN bits should be very rare, and we already have other (more common) cases of `const` results depending on unspecified implementation details that can and sometimes do change on compiler updates, namely the layout of `repr(Rust)` types (observable via `size_of` and `offset_of`).
252
+
We can also consider adding a lint against accidentally producing a NaN in CTFE.
246
253
247
254
### Alternative: `const` tracks NaN values, fails when their bits matter during compile-time
248
255
@@ -252,6 +259,7 @@ This would keep `const C = 0.0/0.0;` working, but requires `const fn is_nan` to
252
259
However, it would require massive amounts of work in the compile-time interpreter, comparable in complexity to all the work that is already required to support symbolic pointers (and the RFC author doubts that there will be a lot of opportunity for those two kinds of symbolic state to share infrastructure).
253
260
That effort should only be invested if there is a significant payoff.
254
261
The RFC author considers the downsides of unspecified NaN bit patterns being observable in const-evaluation to be minimal, and hence the payoff of this alternative to be low.
262
+
A less invasive approach to dealing with potential problems from NaN non-determinism is to lint against producing NaNs in `const` evaluation.
255
263
256
264
# Prior art
257
265
[prior-art]: #prior-art
@@ -303,3 +311,4 @@ In Rust itself, questions around float semantics have been discussed for a long
303
311
- To support fast-math transformations, separate fast-path intrinsics / types could be introduced in the future (also see [this issue](https://github.com/rust-lang/rust/issues/21690)).
304
312
- There might be a way to specify floating-point operations such that if they return a signaling NaN, then the sign is deterministic.
305
313
However, doing so would require (a) coming up with a suitable specification and then (b) convincing LLVM to adopt that specification.
314
+
- We could have a lint that triggers when a compile-time float operation produces a NaN, as that will usually not be intended behavior.
0 commit comments