13

I wanted to test the behavior of floats near infinity. For that I naively wrote the following code:

#include <limits>
#include <iostream>

int main() {
    constexpr float foo = std::numeric_limits<float>::infinity() - std::numeric_limits<float>::epsilon();
    std::cout << foo << std::endl;
    return foo;
}

The interesting part to me was that this compiles fine in GCC 7.2 but fails on Clang 5 (complaining about non-constexpr assign of foo).

AFAIK, since C++11, std::numeric_limits<float>::infinity() and infinity() are constexpr, so I am wondering where the problem lies for Clang.


EDIT 1:

Removed unnecessary static_assert. Thanks for pointing to division by 0. IMO the quoted standards text there does not apply here!?

And the obligatory godbolt link: https://godbolt.org/g/Nd5yF9

EDIT 2:

Note that the same behavior applies to:

constexpr float foo = std::numeric_limits<float>::infinity() - 100.0f;
abergmeier
  • 13,224
  • 13
  • 64
  • 120
  • 6
    Posting the *exact* error message would be a good first step.. – Jesper Juhl Sep 22 '17 at 20:20
  • Do note that this [does not compile](https://godbolt.org/g/41fUVr) on gcc. The `static_assert` fails. Similar for Visual C++ – Justin Sep 22 '17 at 20:23
  • 1according to CLang online docs, since v3.3 C++11 is fully supported [https://clang.llvm.org/cxx_status.html]. Can you please browse your include files and search for multiple and check what is inside? Of course a full error message will help. – j4x Sep 22 '17 at 20:24
  • 2
    Also note that the problem with clang is with the `-`; this works: https://godbolt.org/g/ZyUgJw – Justin Sep 22 '17 at 20:24
  • 2
    Possible duplicate of [Floating point division by zero not constexpr](https://stackoverflow.com/questions/30459773/floating-point-division-by-zero-not-constexpr) – Justin Sep 22 '17 at 20:26
  • @Justin can you give a quick summary why you think this applies here? – abergmeier Sep 22 '17 at 20:35
  • 1
    @abergmeier Upon reading further, I don't think this is a duplicate, but it's certainly related. – Justin Sep 22 '17 at 20:37

1 Answers1

10

I'm not particularly familiar with floating point rules, but I'd suspect that we might be running afoul of [expr]/4:

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.

Which, in turn, means we run afoul of [expr.const]/2.6:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions: [...] an operation that would have undefined behavior as specified in [intro] through [cpp] of this document

That means the initializer for foo isn't a constant expression, so we can't initialize a constexpr object with it.


If infinity() - epsilon() is well-defined for float, this is a clang bug, the code is well-formed. If it's not well-defined for float, this is a gcc bug.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 11
    Or it could be well-defined for one but not the other :D [Clang's constexpr evaluator](https://github.com/llvm-mirror/clang/blob/362362f51fcee8fdc49e0a2e15ad7b43c4f7fa76/lib/AST/ExprConstant.cpp#L2137) is definitely treating all infinity-or-NaN producing expressions as UB. The C++ standard has very little to say about floating point. – T.C. Sep 22 '17 at 21:05