Skip to content

Commit 9042b9e

Browse files
committed
add some notes and comments from the lang team discussion
1 parent 0b79630 commit 9042b9e

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

text/0000-float-semantics.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Unless noted otherwise, the same rules also apply to NaNs returned by other libr
9090

9191
### `const` semantics
9292

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.
9494
`const` use of floating points does not make any guarantees beyond that:
9595
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.
9696
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));
126126
The first assertion is very unlikely to fail in practice (it would require the two invocations of `div` to be optimized differently).
127127
The second however [actually fails](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=0b4b952929c9ebcd2bd50aee54e6cdf4) on current nightlies in debug mode.
128128

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+
129132
This resolves the last open question blocking floating-point operations in `const fn`.
130133
When the RFC is accepted, the `const_fn_floating_point_arithmetic` feature gate and the `const fn to_bits` methods can be stabilized.
131134

@@ -151,6 +154,9 @@ Furthermore, observing the floating-point exception state yields entirely unspec
151154
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.
152155
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.
153156
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.
154160

155161
### Target-specific problems
156162

@@ -243,6 +249,7 @@ Even under this alternative we would allow `const fn` to perform operations that
243249

244250
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.
245251
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.
246253

247254
### Alternative: `const` tracks NaN values, fails when their bits matter during compile-time
248255

@@ -252,6 +259,7 @@ This would keep `const C = 0.0/0.0;` working, but requires `const fn is_nan` to
252259
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).
253260
That effort should only be invested if there is a significant payoff.
254261
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.
255263

256264
# Prior art
257265
[prior-art]: #prior-art
@@ -303,3 +311,4 @@ In Rust itself, questions around float semantics have been discussed for a long
303311
- 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)).
304312
- There might be a way to specify floating-point operations such that if they return a signaling NaN, then the sign is deterministic.
305313
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

Comments
 (0)