Bug 49813 - [C++0x] sinh vs asinh vs constexpr
Summary: [C++0x] sinh vs asinh vs constexpr
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: 4.7.0
Assignee: Paolo Carlini
URL:
Keywords:
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2011-07-22 10:33 UTC by Paolo Carlini
Modified: 2020-03-11 16:39 UTC (History)
7 users (show)

See Also:
Host:
Target: x86_64-linux
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-07-22 14:41:46


Attachments
Library bits, passes testing, the isinf overload for long double cannot be marked constexpr (3.00 KB, patch)
2011-07-25 11:57 UTC, Paolo Carlini
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Paolo Carlini 2011-07-22 10:33:09 UTC
Hi. This issue, pointed out in private email by Vincenzo, puzzles me, I'm not even sure whether it's a C++ proper or an optimization issue related to the way we are lately able to optimize at compile time, mathematical functions of compile time constant arguments. To be safe, I'm adding in CC both Jason and Richi.

(Note, I'm using math.h instead of cmath for avoidance of doubt that this may have to do with the library...)

//////////////

#include <math.h>

int main()
{
  constexpr double ds  = sinh(1.0);   // Ok
  constexpr double das = asinh(1.0);  // Doesn't compile.
}
Comment 1 Richard Biener 2011-07-22 10:38:42 UTC
We do have code to constant fold asinh in builtins.c:

static tree
fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
{
...
    CASE_FLT_FN (BUILT_IN_ASINH):
      if (validate_arg (arg0, REAL_TYPE))
        return do_mpfr_arg1 (arg0, type, mpfr_asinh, NULL, NULL, 0);
    break;

It works for C:

#include <math.h>

int main()
{
    const double ds  = sinh(1.0);   // Ok
    const double das = asinh(1.0);  // Doesn't compile.
}

in the .original dump:

;; Function main (null)
;; enabled by -tree-original


{
  const double ds = 1.175201193643801378385660427738912403583526611328125e+0;
  const double das = 8.8137358701954304773806825323845259845256805419921875e-1;

    const double ds = 1.175201193643801378385660427738912403583526611328125e+0;
    const double das = 8.8137358701954304773806825323845259845256805419921875e-1;
}
Comment 2 Richard Biener 2011-07-22 10:41:36 UTC
With C++ I get

> ./cc1plus -quiet t.c -fdump-tree-original -std=c++0x
t.c: In function 'int main()':
t.c:6:39: error: 'asinh' was not declared in this scope

without -std=c++0x the asinh declaration is there (this seems to be
a glibc issue?).  Look at the output from -dD -E -std=c++0x vs. w/o -std=c++0x.
Comment 3 Richard Biener 2011-07-22 10:48:09 UTC
Because __STRICT_ANSI__ is defined.  Works with -std=gnu++0x.
Comment 4 Paolo Carlini 2011-07-22 10:48:51 UTC
Richard, we need a target here, because not all targets have asinh (a C99 function) in math.h.

Otherwise, if you take out constexpr, of course it works. Only with constexpr the issue is interesting, because, roughly speaking, it looks like the front-end doesn't realize that the whole initialization of das can happen at compile time. But I'm confused here, because I don't know the details about the way the C++0x front-end figures out whether a function *not* marked constexpr, like asinh, actually is being called with compile time constant argument and thus calling it to initialize constexpr data is fine.
Comment 5 Paolo Carlini 2011-07-22 10:52:03 UTC
We don't want this to depend on -std=gnu++0x vs -std=c++0x!!

The function is there, declared and callable, as removing constexpr reveals, the behavior wrt constexpr data cannot depend on __STRICT_ANSI__.
Comment 6 rguenther@suse.de 2011-07-22 10:56:51 UTC
On Fri, 22 Jul 2011, paolo.carlini at oracle dot com wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #5 from Paolo Carlini <paolo.carlini at oracle dot com> 2011-07-22 10:52:03 UTC ---
> We don't want this to depend on -std=gnu++0x vs -std=c++0x!!
> 
> The function is there, declared and callable, as removing constexpr reveals,
> the behavior wrt constexpr data cannot depend on __STRICT_ANSI__.

No, with -std=c++0x asinh is not declared and I get the error above.
With -std=gnu++0x the testcase works for me, even with constexpr.

No bug here.
Comment 7 Paolo Carlini 2011-07-22 11:02:01 UTC
I just tried. This:

#include <math.h>

int main()
{
  double ds  = sinh(1.0);
  double das = asinh(1.0);
}

this compiles fine with -std=c++0x for me. On Linux of course, other targets have specific issues not relevant here. Or, for that matter:

#include <cmath>

int main()
{
  double ds  = std::sinh(1.0);
  double das = std::asinh(1.0);
}

we *really* want the latter to work fine both with -std=c++0x and -std=gnu++0x.
Comment 8 vincenzo Innocente 2011-07-22 11:06:41 UTC
what about other "new C99 functions" such as
cexprMath.cpp:16:64: error: 'float std::nextafter(float, float)' is not
'constexpr'
cexprMath.cpp:17:58: error: 'float std::trunc(float)' is not 'constexpr'
cexprMath.cpp:18:48: error: 'float std::lgamma(float)' is not 'constexpr'
cexprMath.cpp:19:46: error: 'float std::erfc(float)' is not 'constexpr'
?
have not tested all (yet).

from
#include <cmath>

struct foo {
  static constexpr float a = std::cos(3.);
  static constexpr float c = std::exp(3.);
  static constexpr float d = std::log(3.);
  static constexpr float e1 = std::asin(1.);
  static constexpr float h = std::sqrt(.1);
  static constexpr float p = std::pow(1.3,-0.75);
  static constexpr float es = std::sinh(1.);
  static constexpr float ec = std::cosh(1.);
  static constexpr float et = std::tanh(1.);
  static constexpr float zs = std::asinh(1.2);
  static constexpr float zc = std::acosh(1.2);
  static constexpr float zt = std::atanh(.5);
  static constexpr float pi1 =std::nextafter(std::cos(-1.f),0.f);
  static constexpr float three =std::trunc(std::cos(-1.f));
  static constexpr float l0 = std::lgamma(0.45f);
  static constexpr float er = std::erfc(0.45f);

};



as we are on the subject:
if the argument of the function is invalid such as

  static constexpr float nan1 = std::asin(1.45f);
  static constexpr float nan2 = std::sqrt(-1.45f);
I get exactly the same error as above which is a bit confusing

cexprMath.cpp:20:48: error: call to non-constexpr function 'float std::asin(float)'
cexprMath.cpp:20:48: error: field initializer is not constant
cexprMath.cpp:21:49: error: call to non-constexpr function 'float std::sqrt(float)'
cexprMath.cpp:21:49: error: field initializer is not constant

(the test of the message has changed between 4.6 and 4.7)
Comment 9 Paolo Carlini 2011-07-22 11:09:55 UTC
Yes, Vincenzo, all the other C99-only functions should be audited. I suppose a clean fix will automatically deal with all of them.
Comment 10 rguenther@suse.de 2011-07-22 11:17:38 UTC
On Fri, 22 Jul 2011, paolo.carlini at oracle dot com wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #9 from Paolo Carlini <paolo.carlini at oracle dot com> 2011-07-22 11:09:55 UTC ---
> Yes, Vincenzo, all the other C99-only functions should be audited. I suppose a
> clean fix will automatically deal with all of them.

Looking at -original it seems that libstdc++ lacks C99 overloads for
double - it has them for float and long double only.

Or that

  inline float
  asinh(float __x)
  { return __builtin_asinhf(__x); }

  inline long double
  asinh(long double __x)
  { return __builtin_asinhl(__x); }

  template<typename _Tp>
    inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
                                           double>::__type
    asinh(_Tp __x)
    { return __builtin_asinh(__x); }

isn't constexpr compatible.

Doesn't sound like a middle-end issue but either a library or frontend
issue to me.

That said, it works fine if you give a asinh declaration in the
testcase.

Richard.
Comment 11 Paolo Carlini 2011-07-22 11:20:36 UTC
It does *not* Richi, there is an using ::asinh above. Exactly the same for sinh.
Comment 12 rguenther@suse.de 2011-07-22 11:20:52 UTC
On Fri, 22 Jul 2011, rguenther at suse dot de wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #10 from rguenther at suse dot de <rguenther at suse dot de> 2011-07-22 11:17:38 UTC ---
> On Fri, 22 Jul 2011, paolo.carlini at oracle dot com wrote:
> 
> > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> > 
> > --- Comment #9 from Paolo Carlini <paolo.carlini at oracle dot com> 2011-07-22 11:09:55 UTC ---
> > Yes, Vincenzo, all the other C99-only functions should be audited. I suppose a
> > clean fix will automatically deal with all of them.
> 
> Looking at -original it seems that libstdc++ lacks C99 overloads for
> double - it has them for float and long double only.
> 
> Or that
> 
>   inline float
>   asinh(float __x)
>   { return __builtin_asinhf(__x); }
> 
>   inline long double
>   asinh(long double __x)
>   { return __builtin_asinhl(__x); }
> 
>   template<typename _Tp>
>     inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
>                                            double>::__type
>     asinh(_Tp __x)
>     { return __builtin_asinh(__x); }
> 
> isn't constexpr compatible.
> 
> Doesn't sound like a middle-end issue but either a library or frontend
> issue to me.
> 
> That said, it works fine if you give a asinh declaration in the
> testcase.

Btw, asinh is

  template<typename _Tp>
    inline typename __gnu_cxx::__promote<_Tp>::__type
    asinh(_Tp __x)
    {
      typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
      return asinh(__type(__x));
    }

vs. sinh which is

  template<typename _Tp>
    inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
        double>::__type
    sinh(_Tp __x)
    { return __builtin_sinh(__x); }

note the lack of __gnu_cxx::__promote
Comment 13 Paolo Carlini 2011-07-22 11:24:21 UTC
... and let's decide to look at mainline, first at least.
Comment 14 rguenther@suse.de 2011-07-22 11:29:04 UTC
On Fri, 22 Jul 2011, paolo.carlini at oracle dot com wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #11 from Paolo Carlini <paolo.carlini at oracle dot com> 2011-07-22 11:20:36 UTC ---
> It does *not* Richi, there is an using ::asinh above. Exactly the same for
> sinh.

There is also a using ::asinhf but still std:: provides an
overload.

Please provide a _complete_ standalone testcase that you think should
work and does not (w/o any includes).

I suspect it's because of

DEF_C99_BUILTIN        (BUILT_IN_CASINH, "casinh", 
BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE, ATTR_MATHFN_FPROUNDING)

so if -std=c++0x does not include C99 functions then we have no
implicit builtin support and the following does not work:

extern "C" double asinh(double x);

namespace std {
    using ::asinh;
}

int main()
{
  constexpr double das = std::asinh(1.0);
}

it also does not work with

namespace std {
    double asinh (double x) { return __builtin_asinh (x); }
}

int main()
{
  constexpr double das = std::asinh(1.0);  // Doesn't compile.
}

but it works with

int main()
{
  constexpr double das = __builtin_asinh(1.0);  // Doesn't compile.
}

which means this is still a C++ frontend / library issue.
Comment 15 Richard Biener 2011-07-22 11:30:38 UTC
Also works with

namespace std {
    constexpr double asinh (double x) { return __builtin_asinh (x); }
}

int main()
{
  constexpr double das = std::asinh(1.0);  
}
Comment 16 Paolo Carlini 2011-07-22 11:40:07 UTC
(In reply to comment #14)
> There is also a using ::asinhf but still std:: provides an overload.

So? This is what C++0x says we should have.

As regards a complete testcase, I gave two, one using <math.h>, one a *real world* piece of C++0x code, compiled with -std=c++0x on Linux.

#include <cmath>

int main()
{
  constexpr double cds  = std::sinh(1.0);  // Ok
  constexpr double cdas = std::asinh(1.0); // Not Ok.
  double das = std::asinh(1.0);            // Ok.
}

we don't want those inconsistencies.

By the way, I find your:

constexpr double cdas = __builtin_asinh(1.0);

very interesting. Looks like really the front-end is doing something strange wrt declarations of C99 functions: if <math.h> provided by glibc is include then the declarations are definitely there, in strict c++0x mode too, but the front-end is trying to invent something on its own, disregards those declarations somehow, but *only* when dealing with constexpr data, not otherwise.
Comment 17 rguenther@suse.de 2011-07-22 11:43:57 UTC
On Fri, 22 Jul 2011, paolo.carlini at oracle dot com wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #16 from Paolo Carlini <paolo.carlini at oracle dot com> 2011-07-22 11:40:07 UTC ---
> (In reply to comment #14)
> > There is also a using ::asinhf but still std:: provides an overload.
> 
> So? This is what C++0x says we should have.
> 
> As regards a complete testcase, I gave two, one using <math.h>, one a *real
> world* piece of C++0x code, compiled with -std=c++0x on Linux.
> 
> #include <cmath>
> 
> int main()
> {
>   constexpr double cds  = std::sinh(1.0);  // Ok
>   constexpr double cdas = std::asinh(1.0); // Not Ok.
>   double das = std::asinh(1.0);            // Ok.
> }
> 
> we don't want those inconsistencies.
> 
> By the way, I find your:
> 
> constexpr double cdas = __builtin_asinh(1.0);
> 
> very interesting. Looks like really the front-end is doing something strange
> wrt declarations of C99 functions: if <math.h> provided by glibc is include
> then the declarations are definitely there, in strict c++0x mode too, but the
> front-end is trying to invent something on its own, disregards those
> declarations somehow, but *only* when dealing with constexpr data, not
> otherwise.

Is it valid in C++0x to provide a global function

double asinh (double x)
{
  abort ();
}

?  In that case we can't inject __builtin_asinh as asinh into the
global namespace (as -std=gnu++0x does) and the using ::asinh
is bogus(?)

If the above is invalid then with -std=c++0x the C++ frontend should
set flag_iso_c99 to true.

Richard.
Comment 18 Paolo Carlini 2011-07-22 12:31:05 UTC
Before any other discussion (I believe we want to hear Jason now) I only want to add this: I think the whole discussion about -std=c++0x vs -std=gnu++0x can only possibly be useful in so far as it helps figuring out where is the bug. Because, really, part of the C++11 standard is certainly the unconditional availability of all of the C99 mathematical functions (more generally, the reference C language is everywhere C99 instead of C89, as it should be in 2011). Thus, I don't know at this point where exactly is the bug/issue, in the front-end, in some glibc bits vs C++11, in interactions, but I'm pretty sure we *do* have an issue here. To restate, from the C++11 point of view, sinh and asinh are 100% on a par. If we see an inconsistency in our implementers "world" about the way we are dealing in strict c++0x mode with those mathematical functions, it's our fault, a bug or a QoI issue.
Comment 19 Jason Merrill 2011-07-22 14:41:46 UTC
Strictly speaking, the bug is that

  constexpr double ds  = sinh(1.0);   // Ok

is accepted; the standard doesn't say that sinh is constexpr, so it isn't usable in a constant expression.  G++ treating built-ins as constexpr is an extension, which should be disabled in strict conformance mode.  Paolo, can you raise the question of marking C library functions as constexpr with the library WG?

But practically speaking, we should have C90 builtins in C++98, and C99 builtins in C++11.  I suppose that means setting flag_isoc94 and flag_isoc99 in C++.
Comment 20 Paolo Carlini 2011-07-22 15:07:53 UTC
I see, everything makes sense now. And OK, I'll raise the issue (in fact, we have Daniel in CC, in this bug... ;)
Comment 21 Paolo Carlini 2011-07-22 15:31:15 UTC
Hum (Jason and Daniel, in particular) I'm wondering if the issue could fall under http://lwg.github.com/issues/lwg-active.html#2013 but then, we would be able to assume / do it only for glibc on which we have control?!? I have no idea if the implementations in the various libc out there all satisfy the prerequisites for a function to be marked constexpr. Do you see my point? Or Jason you mean something else entirely?
Comment 22 Jason Merrill 2011-07-22 16:06:13 UTC
Author: jason
Date: Fri Jul 22 16:06:08 2011
New Revision: 176635

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=176635
Log:
	PR c++/49813
	* c-opts.c (set_std_cxx0x): Set flag_isoc94 and flag_isoc99.
	* c-pretty-print.c (pp_c_cv_qualifiers): Check c_dialect_cxx as well
	as flag_isoc99 for 'restrict'.
	(pp_c_specifier_qualifier_list): Likewise for _Complex.

Added:
    trunk/gcc/testsuite/g++.dg/opt/builtins2.C
Modified:
    trunk/gcc/c-family/ChangeLog
    trunk/gcc/c-family/c-opts.c
    trunk/gcc/c-family/c-pretty-print.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/g++.dg/other/error27.C
Comment 23 vincenzo Innocente 2011-07-22 16:48:35 UTC
would  http://lwg.github.com/issues/lwg-active.html#2013 allow gcc to declare constexpr the x86 builtins (and corresponding wrapper functions)?
I would be interested to have constepxr vectors (__m128 etc)
Comment 24 Paolo Carlini 2011-07-22 17:16:43 UTC
As far as I can see, Vincenzo, in that case the problem is a bit different, because those functions aren't ISO: should Intel issue an updated document describing the builtins and acknowledging the new C++? To be honest I know little about the way those builtins are "standardized", the way Intel issues updates to the specs. Maybe you could open about that a separate "exploratory" Bugzilla (in CC people like Uros)?!?
Comment 25 Daniel Krügler 2011-07-24 14:55:04 UTC
(In reply to comment #21)

As far as I could follow this discussion, LWG 2013 seems to be the right location from the library view of point. But a compiler should not allow for function calls to participate in constant expressions, if these functions are not marked as constexpr. Library functions and other intrinsics can probably be considered as exceptions, because they are not required to be "explainable" by normal language rules.
Comment 26 Jason Merrill 2011-07-25 05:11:35 UTC
Ah, yes, LWG 2013 does seem to allow GCC to treat these functions as constexpr. So, fixed for 4.7.
Comment 27 Paolo Carlini 2011-07-25 10:19:17 UTC
Thanks Jason.

Let's reopen this as a library issue now: I have to mark constexpr the C++0x library provided overloads (for float, long double, double too for the C90 functions). Will do momentarily.
Comment 28 Paolo Carlini 2011-07-25 10:21:57 UTC
(I meant to say -some- C90 functions, like std::abs, in most of the cases only the overloads for float and long double require work)
Comment 29 Richard Biener 2011-07-25 10:45:59 UTC
(In reply to comment #28)
> (I meant to say -some- C90 functions, like std::abs, in most of the cases only
> the overloads for float and long double require work)

You have to be careful though as we do not guarantee to fold things in
the middle-end.  For example I don't think mpfr handles all exceptional
values, so we might end up not folding those (like with -fsignalling-nans
or signed zeros).  Also for -frounding-math we do not constant fold
floating point expressions.

But I'm not sure what guarantee a constexpr marked overload of, say,
sqrt provides.  We at least don't fold sqrt (-1.0).
Comment 30 Paolo Carlini 2011-07-25 10:51:19 UTC
Jason, looks like we have a remaining curious C++ front-end issue with isinf for long double, see the below. Can you have a look? Thanks!

Paolo.

//////////////////

inline constexpr bool
isinf(long double __x)
{ return __builtin_isinf(__x); }

inline constexpr bool
isinf(double __x)
{ return __builtin_isinf(__x); }

inline constexpr bool
isnan(long double __x)
{ return __builtin_isnan(__x); }

int main()
{
  constexpr long double num1 = __builtin_isinf(1.l); // Ok.

  constexpr long double num2 = isinf(1.l);           // Error.

  constexpr double      num3 = isinf(1.);            // Ok.

  constexpr long double num4 = isnan(1.l);           // Ok.
}
Comment 31 Paolo Carlini 2011-07-25 10:54:24 UTC
Richard, as far as I can see, if we don't fold, we don't fold, that line of user code with, eg constexpr data, will simply not compile. I don't think this is a major issue...
Comment 32 rguenther@suse.de 2011-07-25 10:59:30 UTC
On Mon, 25 Jul 2011, paolo.carlini at oracle dot com wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #31 from Paolo Carlini <paolo.carlini at oracle dot com> 2011-07-25 10:54:24 UTC ---
> Richard, as far as I can see, if we don't fold, we don't fold, that line of
> user code with, eg constexpr data, will simply not compile. I don't think this
> is a major issue...

Ah, ok.  So a constexpr function only means the frontend has to "try"
to constant-fold it, and if it doesn't fold to a constant it's an
errorneous program.  I suppose only if the result is used in a
constexpr, that is (recursively so).
Comment 33 vincenzo Innocente 2011-07-25 11:02:26 UTC
indeed
as noted in comment 8

    20	  static constexpr float nan1 = std::asin(1.45);
    21	  static constexpr float nan2 = std::sqrt(-1.45);
produces the quite confusion error message:
cexprMath.cpp:20:47: error: field initializer is not constant
cexprMath.cpp:21:48: error: field initializer is not constant
something saying that the argument is out-of-range may be more appropriate
Comment 34 Paolo Carlini 2011-07-25 11:17:24 UTC
Better diagnostic would be always welcome, but probably we should deal with that elsewhere (we *do* have PRs about constexpr vs diagnostics), because it's a generic problem, isn't specific to the math functions in the library (quite a special case actually, because C++11 does *not* even mandate those functions to be constexpr)
Comment 35 Paolo Carlini 2011-07-25 11:41:57 UTC
Also, something seems wrong with nextafter, but for the intrinsic too this time, thus maybe is a middle-end issue (eg, not optimized at all?). Try:

  constexpr float na = __builtin_nextafter(0.0f, 0.0f);
Comment 36 Paolo Carlini 2011-07-25 11:43:02 UTC
Or, more correctly:

  constexpr float na = __builtin_nextafterf(0.0f, 0.0f);
Comment 37 rguenther@suse.de 2011-07-25 11:44:12 UTC
On Mon, 25 Jul 2011, paolo.carlini at oracle dot com wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #35 from Paolo Carlini <paolo.carlini at oracle dot com> 2011-07-25 11:41:57 UTC ---
> Also, something seems wrong with nextafter, but for the intrinsic too this
> time, thus maybe is a middle-end issue (eg, not optimized at all?). Try:
> 
>   constexpr float na = __builtin_nextafter(0.0f, 0.0f);

Not all functions are folded by the middle-end.  Look into builtins.c.
Patches welcome.
Comment 38 Paolo Carlini 2011-07-25 11:46:00 UTC
Ah Ok, maybe I will be able to work on that. Just wanted to make sure we understand where the problem is.
Comment 39 Paolo Carlini 2011-07-25 11:49:33 UTC
(however, the issue in Comment #30, isinf vs long double, seems a real glitch somewhere, the intrinsic works fine)
Comment 40 Paolo Carlini 2011-07-25 11:57:58 UTC
Created attachment 24826 [details]
Library bits, passes testing, the isinf overload for long double cannot be marked constexpr
Comment 41 Paolo Carlini 2011-07-25 19:58:52 UTC
The testcase in Comment #30 has the types wrong, the below is a corrected version (the substance of the issue doesn't change at all). I'm also thinking of checking in the library bits with a temporary workaround of the form:

  inline constexpr bool
  isinf(long double __x)
  { return fpclassify(__x) == FP_INFINITE; }

which works.

/////////////

inline constexpr bool
isinf(long double __x)
{ return __builtin_isinf(__x); }

inline constexpr bool
isinf(double __x)
{ return __builtin_isinf(__x); }

inline constexpr bool
isnan(long double __x)
{ return __builtin_isnan(__x); }

int main()
{
  constexpr  int i1 = __builtin_isinf(1.l);  // Ok.
  constexpr bool b2 = isinf(1.l);            // Error.
  constexpr bool b3 = isinf(1.);             // Ok.
  constexpr bool b4 = isnan(1.l);            // Ok.
}
Comment 42 Jason Merrill 2011-07-26 00:10:20 UTC
(In reply to comment #34)
> (we *do* have PRs about constexpr vs diagnostics)

Notably 45923, which I have just closed as fixed by my June 29 patch.

The comment 8 testcase results in errors like

wa.C:16:64: error: call to non-constexpr function ‘float std::nextafter(float, float)’
wa.C:16:64: error: field initializer is not constant
...

which seems plenty clear to me: the initializer is not constant because of the call to a non-constexpr function.

The isinf issue has to do with the (...) signature; morally_constexpr_builtin_function_p rejects varargs.  Seems like we should add BUILT_IN_ISINF and its variants to builtin_valid_in_constant_expr_p.
Comment 43 Jason Merrill 2011-07-26 00:26:26 UTC
(In reply to comment #42)
> Seems like we should add BUILT_IN_ISINF and its variants to
> builtin_valid_in_constant_expr_p.

Actually, we seem to ignore the arguments when a function satisfies that function, which isn't what we want.  Probably morally_constexpr_builtin_function_p should be rewritten to just have an enumeration of suitable builtins, and then move into builtins.c with a different name, right after is_inexpensive_builtin.
Comment 44 Paolo Carlini 2011-07-26 00:29:22 UTC
Please.. ;)
Comment 45 Paolo Carlini 2011-07-27 16:48:55 UTC
I have just noticed that with -m32 the isinf overloads for float and double are also affected, that is:

constexpr bool
isinf(float __x)
{ return __builtin_isinf(__x); }

constexpr bool
isinf(double __x)
{ return __builtin_isinf(__x); }
Comment 46 Paolo Carlini 2011-07-27 17:18:55 UTC
Another note, about std::nextafter, std::nexttoward, & co: I see mpfr provides an mpfr_nexttoward, which likely could be exploited in builtins.c pretty easily. 

Kaveh, do you have any plan about those?
Comment 47 paolo@gcc.gnu.org 2011-07-27 19:33:55 UTC
Author: paolo
Date: Wed Jul 27 19:33:51 2011
New Revision: 176847

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=176847
Log:
2011-07-27  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/49813
	* include/c_global/cmath: Use _GLIBCXX_CONSTEXPR and constexpr.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/c_global/cmath
Comment 48 Kaveh Ghazi 2011-07-27 22:32:57 UTC
(In reply to comment #41)
> The testcase in Comment #30 has the types wrong, the below is a corrected
> version (the substance of the issue doesn't change at all). I'm also thinking
> of checking in the library bits with a temporary workaround of the form:
>   inline constexpr bool
>   isinf(long double __x)
>   { return fpclassify(__x) == FP_INFINITE; }
> which works.
> /////////////
> inline constexpr bool
> isinf(long double __x)
> { return __builtin_isinf(__x); }
> inline constexpr bool
> isinf(double __x)
> { return __builtin_isinf(__x); }
> inline constexpr bool
> isnan(long double __x)
> { return __builtin_isnan(__x); }
> int main()
> {
>   constexpr  int i1 = __builtin_isinf(1.l);  // Ok.
>   constexpr bool b2 = isinf(1.l);            // Error.
>   constexpr bool b3 = isinf(1.);             // Ok.
>   constexpr bool b4 = isnan(1.l);            // Ok.
> }


The isinf (and isinf_sign) functions use the (...) signature, but isinff and isinfl do not.  So if as noted in comment#42 the problem is with the long double variant using ellipses by calling isinf(...), perhaps you can fix it by using __builtin_isinfl (with the trailng "L") in the inline definition.  I'm not sure why isnan passes, cause that one uses ellipses for the double variant also.  Probably best to fix all the inlines to use the specific "L" or "F" function.
Comment 49 Paolo Carlini 2011-07-27 22:56:10 UTC
Thanks for your feedback Kaveh. Note, however, that, as I mentioned only today in Comment #45, with -m32 we have problems also with the overload for double, I have no idea how to fix it. More generally, I would be *really* curious to understand what's so special about isinf vs isnan and the other classification facilities, only isinf gives me troubles...
Comment 50 Kaveh Ghazi 2011-07-27 23:13:18 UTC
(In reply to comment #46)
> Another note, about std::nextafter, std::nexttoward, & co: I see mpfr provides
> an mpfr_nexttoward, which likely could be exploited in builtins.c pretty
> easily. 
> Kaveh, do you have any plan about those?

It's been several years since I did the mpfr work so my memory is a little foggy, but I think I intentionally skipped the next* functions.  IIRC, these functions are very sensitive to the target floating point format.  It wasn't clear to me that the "next" FP value in mpfr actually corresponded to the "next" value in the target FP format or how to verify if it was so.  (I'm thinking mainly of the non-ieee formats here.)  

If these odd formats aren't used in GCC anymore then it might be okay to implement the builtins using mpfr.  Alternatively, you can implement the builtins only for the formats where mpfr's format is identical to the target fp format.  But then the optimization won't work everywhere so your library testcase will fail on some cpus.

I'm not sure it's worth the trouble (and to answer your question I don't have any plans to work on it.)
Comment 51 Jakub Jelinek 2011-07-28 06:47:43 UTC
It isn't hard to implement it ourselves just on the REAL_VALUE_TYPE type.
We'd just need to handle a few special cases (e.g. x NaN or y NaN I guess we'd normally just don't optimize), and then we'd just add_significand/sub_significand of all zeros but LSB bit set, if it returns non-zero, bump/decrease exponent if possible, if not possible, give up/set to zero.
Comment 52 rguenther@suse.de 2011-07-28 09:26:40 UTC
On Wed, 27 Jul 2011, ghazi at gcc dot gnu.org wrote:

> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49813
> 
> --- Comment #50 from Kaveh Ghazi <ghazi at gcc dot gnu.org> 2011-07-27 23:13:18 UTC ---
> (In reply to comment #46)
> > Another note, about std::nextafter, std::nexttoward, & co: I see mpfr provides
> > an mpfr_nexttoward, which likely could be exploited in builtins.c pretty
> > easily. 
> > Kaveh, do you have any plan about those?
> 
> It's been several years since I did the mpfr work so my memory is a little
> foggy, but I think I intentionally skipped the next* functions.  IIRC, these
> functions are very sensitive to the target floating point format.  It wasn't
> clear to me that the "next" FP value in mpfr actually corresponded to the
> "next" value in the target FP format or how to verify if it was so.  (I'm
> thinking mainly of the non-ieee formats here.)  
> 
> If these odd formats aren't used in GCC anymore then it might be okay to
> implement the builtins using mpfr.  Alternatively, you can implement the
> builtins only for the formats where mpfr's format is identical to the target fp
> format.  But then the optimization won't work everywhere so your library
> testcase will fail on some cpus.
> 
> I'm not sure it's worth the trouble (and to answer your question I don't have
> any plans to work on it.)

I think the next* functions should be done with real.c stuff as it could
be indeed dependent on the target format.

Richard.
Comment 53 Steve Ellcey 2011-07-28 20:59:15 UTC
Author: sje
Date: Thu Jul 28 20:59:11 2011
New Revision: 176899

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=176899
Log:
2011-07-28  Paolo Carlini  <paolo.carlini@oracle.com>

        PR c++/49813
        * semantics.c (potential_constant_expression_1):  Handle FMA_EXPR.

	Checking this in for Paolo.

Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/semantics.c
Comment 54 Jason Merrill 2011-08-01 18:14:32 UTC
Author: jason
Date: Mon Aug  1 18:14:29 2011
New Revision: 177066

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=177066
Log:
	PR c++/49813
	* semantics.c (potential_constant_expression_1): Allow any builtin.
	(morally_constexpr_builtin_function_p): Remove.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-builtin1.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/semantics.c
    trunk/gcc/testsuite/ChangeLog
Comment 55 Jason Merrill 2011-08-01 18:27:58 UTC
I've changed the compiler to allow all builtins in constexpr functions.
Comment 56 paolo@gcc.gnu.org 2011-08-01 19:26:42 UTC
Author: paolo
Date: Mon Aug  1 19:26:39 2011
New Revision: 177070

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=177070
Log:
2011-08-01  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/49813
	* include/c_global/cmath (isinf): Remove workaround.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/c_global/cmath
Comment 57 Paolo Carlini 2011-08-11 17:33:01 UTC
Any objections to adding to the Wiki a list of the intrinsics not yet folded by the middle-end as an open project? Or we do already have such a list somewhere (beyond inspecting builtins.c)?
Comment 58 Paolo Carlini 2011-09-20 23:45:12 UTC
I think this is completely done by now.
Comment 59 Shafik Yaghmour 2014-12-31 14:59:52 UTC
The resolution of LWG 2013 changed: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3788.html#2013 and it no longer gives implementation the freedom to treat standard library functions as constexpr unless it is explicitly required. The new wording was included in the draft standard since at least N3936.

Although a strict reading seems to leave some wiggle room the intention as mentioned in the updated issue was to avoid "diverging library implementations, as users may use SFINAE to observe different behavior from otherwise identical code".
Comment 60 Jonathan Wakely 2020-03-11 16:31:24 UTC
There's no wiggle room, we're definitely non-conforming.

Maybe the changes could be limited to -std=gnu++NN modes only, although Paolo argued strongly against that in this bug report.

It doesn't seem to be causing any issues for anybody though, so I'm not very motivated to "fix" our non-conformance by removing features (and probably breaking somebody's code).
Comment 61 Jakub Jelinek 2020-03-11 16:39:21 UTC
(In reply to Jonathan Wakely from comment #60)
> There's no wiggle room, we're definitely non-conforming.
> 
> Maybe the changes could be limited to -std=gnu++NN modes only, although
> Paolo argued strongly against that in this bug report.
> 
> It doesn't seem to be causing any issues for anybody though, so I'm not very
> motivated to "fix" our non-conformance by removing features (and probably
> breaking somebody's code).

I'd say we should (but perhaps for GCC11 only) remove those constexpr markings and users that really need constexpr behavior will just need to use __builtin_sinh etc. instead which ought to be constexpr because it is a builtin.