[clang] [C++23] [CLANG] Adding C++23 constexpr math functions: fmin and frexp. (PR #88978)

Joshua Cranmer via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 23 12:53:47 PDT 2024


================
@@ -2922,7 +2922,7 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E,
   //   If during the evaluation of an expression, the result is not
   //   mathematically defined [...], the behavior is undefined.
   // FIXME: C++ rules require us to not conform to IEEE 754 here.
-  if (LHS.isNaN()) {
+  if (!Info.getLangOpts().CPlusPlus23 && LHS.isNaN()) {
----------------
jcranmer-intel wrote:

https://eel.is/c++draft/library.c#3 says that

>A call to a C standard library function is a non-constant library call ([defns.nonconst.libcall]) if it raises a floating-point exception other than FE_INEXACT.)"

which suggests that floating-point exceptions should generally cause things to fall out of constant expressions. C's Annex F suggests that warnings be emitted for constant expressions that cause floating-point exceptions other than FE_INEXACT (see F.8.2p2).

As for wording, [expr.pre]p4 requires that things be "mathematically defined", except IEEE 754 specifically says (in section 3.2)

> The mathematical structure underpinning the arithmetic in this standard is the extended reals, that is, the set
of real numbers together with positive and negative infinity.

The C++ specification actually does define "mathematically defined" somewhere, in a footnote of https://eel.is/c++draft/sf.cmath.general:

> A mathematical function is mathematically defined for a given set of argument values (a) if it is explicitly defined for that set of argument values, or (b) if its limiting value exists and does not depend on the direction of approach.

(which, as pendants will note, only defines it for functions, not the base operations of C++, and sidesteps the question of what the set of argument values actually is).

It does seem pretty clear from all the standards that a result of infinity is clearly part of the representable types, and it seems a reasonable inference that the result being infinity is "mathematically defined" (division by 0 is permissible in the extended real numbers).

The role of NaNs is... clear as mud. You have to go into the definition of <limits> to find out that NaN is a representable value. IEEE 754 gives multiple specification levels for floating-point, where NaN is a part of some of them, and proceeds to ignore the fact that it did so in the rest of the specification; the definition of operations involving NaN is deferred into an entire separate section. Section 7.2 goes so far as to say that

> The invalid operation exception is signaled if and only if there is no usefully definable result. In these cases
the operands are invalid for the operation to be performed.

Is `0.0 / 0.0` "mathematically defined" per IEEE 754? It's definitely *defined*, but I don't think I can entirely endorse saying that it's "mathematically defined." The rule of thumb that FE_INVALID is signaled when the inputs are non-qNaN but the output is NaN, combined with the above text, makes it suspect that it should be considered a "mathematical" definition. But this also doesn't help with `NaN / NaN`, which is `NaN` but doesn't throw a FE_INVALID.

As noted in the CWG issue Aaron linked to, someone needs to write a paper to clarify this, and... that's going to be me isn't it?

https://github.com/llvm/llvm-project/pull/88978


More information about the cfe-commits mailing list