It's hard to tell how __builtin_constant_p works right now, due to PR54020. // Preliminaries. extern int nonconst_func(int); constexpr int identity(int x) { return x; } constexpr int zero() { return identity(0); } constexpr int one() { return identity(1); } // These are the same. Only the latter is accepted, though. // I suspect that the acceptance of the latter is due to the bug above. constexpr int rejected_const_4(int x) { return __builtin_constant_p(x) ? 4 : nonconst_func(x); } constexpr int accepted_const_4(int x) { return identity(__builtin_constant_p(x)) ? 4 : nonconst_func(x); } // This is rejected. I would like it to work. constexpr int four = accepted_const_4(1); The ability to use the construction __builtin_constant_p(x) ? const_func(x) : nonconst_func(x) in constexpr context would be quite powerful.
This is rejected only at -O0 and quite matches how __builtin_constant_p normally behaves at -O0 - you really need a constant right in the __builtin_constant_p argument, everything else results in 0. With -O1 and above you get BUILTIN_CONSTANT_P not folded right away to 0 if not constant and whether it in the end folds to 0 or 1 depends on optimization, whether a constant is propagated to it or not.
Perhaps the C++ FE could when parsing a constexpr function during finish_call_expr of __builtin_constant_p just temporarily force optimize = 1 if it is zero to prevent folding it to 0 (or alternatively, if it folds to 0, build it non-folded), it would be an extension over how this builtin behaves right now, on the other side as constexpr is "optimized" even at -O0 it would match the intent of the builtin. The question is if/when it will be actually folded to 0 afterwards if not in constexpr context.
Author: jason Date: Thu Jul 19 20:02:08 2012 New Revision: 189677 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=189677 Log: PR c++/54021 * call.c (build_cxx_call): Set optimize when folding __builtin_constant_p in a constexpr function. Added: trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-builtin2.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c trunk/gcc/testsuite/ChangeLog
I'm not sure when exactly it gets folded later, but it does seem to happen appropriately.
I'm running into some issues with this bug, and it's much broader than the test cases suggest. On gcc 4.7.0, this is what happens: int main() { int x = 0; // This assigns false to a: bool const a = __builtin_constant_p(x); // This assigns true to b: bool const b = __builtin_constant_p(__builtin_constant_p(x)); // This causes "error: the value of 'x' is not usable in a constant expression" constexpr bool c = __builtin_constant_p(x); }
I think that's correct. x isn't a standards-mandated constant expression, so __builtin_constant_p depends on optimization level and probably shouldn't be allowed as a constexpr.
That seems to me like saying that `constexpr bool d = sizeof(x);` should be disallowed because it uses a non-constexpr. You're not using the value of x, just a property about it. Whether a value is constexpr is guaranteed to be known at compile time, and so should be usable as a constexpr.
Did you mean "constexpr bool a" instead of "book const a"? If so, I agree. But consider: bool const a = something complicated Is a a constant?
(In reply to comment #5) > // This causes "error: the value of 'x' is not usable in a constant expression" > constexpr bool c = __builtin_constant_p(x); > } This is also fixed by my patch.