Please see the update for a better sample of the problem. The original code has a mix of issues which muddies the picture:
This question Why can I call a non-constexpr function inside a constexpr function? presented the following code
#include <stdio.h>
constexpr int f()
{
return printf("a side effect!\n");
}
int main()
{
char a[f()];
printf("%zd\n", sizeof a);
}
Which as I answer is ill-formed but gcc 4.8.2
allows it (see it live).
But, if we use the -fno-builtin
flag gcc
generates an error (see it live):
error: call to non-constexpr function 'int printf(const char*, ...)'
return printf("a side effect!\n");
^
so it seems
that gcc
is considering its builtin version of printf
to be a constant expression. gcc
documents builtins here but does not document this case where a builtin of a non-constexpr function can be considered a constant expression.
If this is indeed the case:
1.4
Implementation compliance paragraph 8 says (emphasis mine):A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.
Update
As Casey points out there are a few things going on in the original problem that makes it a poor example. A simple example would be using std::pow which is not a constexpr function:
#include <cmath>
#include <cstdio>
constexpr double f()
{
return std::pow( 2.0, 2.0 ) ;
}
int main()
{
constexpr double x = f() ;
printf( "%f\n", x ) ;
}
Compiles and builds with no warnings or error (see it live) but adding -fno-builtin
makes it generates an error (see it live). Note: why math functions are not constexpr in C++11:
error: call to non-constexpr function 'double pow(double, double)'
return std::pow( 2.0, 2.0 ) ;
^
GCC provides built-in versions of the ISO C99 floating-point comparison macros that avoid raising exceptions for unordered operands. They have the same names as the standard macros ( isgreater , isgreaterequal , isless , islessequal , islessgreater , and isunordered ) , with __builtin_ prefixed.
A constant value is one that doesn't change. C++ provides two keywords to enable you to express the intent that an object is not intended to be modified, and to enforce that intent. C++ requires constant expressions — expressions that evaluate to a constant — for declarations of: Array bounds.
int__builtin_ffs (unsigned int x) Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero. int__builtin_clz (unsigned int x) Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
Yes, gcc
is considering some builtin functions as constexpr even if the standard does not explicitly mark them as such. We can find the discussion that pertains specifically to the math function found in cmath
in the gcc
bug report [C++0x] sinh vs asinh vs constexpr which says:
LWG 2013 does seem to allow GCC to treat these functions as constexpr. So, fixed for 4.7
which is referring to LWG issue 2013 whose original proposed resolution was to add the following to section 17.6.5.6
[constexpr.functions] (emphasis mine going forward):
[...]Additionally, an implementation may declare any function to be constexpr if that function's definition satisfies the necessary constraints[...]
but after C++11 the resolution was reversed and the final resolution ended up as:
[...]An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required.[..]
So this is currently(in C++14) a explicitly non-conforming extension and as far as I can tell this was non-conforming in C++11 since it alters observable behavior and therefore would not be allowed via the as-if rule.
Jonathan Wakely points out a libstdc++
mailing list discussion: PR libstdc++/49813 revisited: constexpr on functions (and builtins) where reopening the bug report mentioned above was discussed due to the issues laid out above:
I believe we should re-open the bug in light of the actual resolution of LWG 2013 (adding constexpr is forbidden).
The FE should not treat builtins as constexpr in strict-conformance mode.
We should either remove _GLIBCXX_CONSTEXPR from <cmath> entirely or make it conditional on __STRICT_ANSI__.
GCC does not consider f()
to be a constant expression. Look at the diagnostics for the first sample program you linked:
main.cpp: In function 'int main()': main.cpp:10:19: warning: ISO C++ forbids variable length array 'a' [-Wvla] char a[f()]; ^
The compiler doesn't think f()
is a constant expression, the program is in fact using GCC's extension that allows variable length arrays - arrays with non-constant size.
If you change the program to force f()
into a constant expression:
int main() {
constexpr int size = f();
char a[size];
printf("%zd\n", sizeof a);
}
GCC does report an error:
main.cpp: In function 'int main()': main.cpp:10:32: in constexpr expansion of 'f()' main.cpp:5:41: error: 'printf(((const char*)"a side effect!\012"))' is not a constant expression return printf("a side effect!\n"); ^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With