Take: int t; int f = __builtin_constant_p(t) ? t : -1; int h[__builtin_constant_p(t) ? t : 1]; --- CUT --- This is accepted by the C front-end by rejected by the C++ front-end. I would assume the built-in function __builtin_constant_p would cause it to be considered as an integer constant expression but for some reason it is not. The manual does say this about using it in static intializers: You may also use __builtin_constant_p in initializers for static data. Which I had hoped it would cause it to be part of the constant integer expression.
This is a bug in the C front-end. They need to use __builtin_choose_expr.
Subject: Re: __builtin_constant_p(t) ? t : 1 is not considered a constant integer expression On Sat, 6 Dec 2008, sabre at nondot dot org wrote: > This is a bug in the C front-end. They need to use __builtin_choose_expr. No, it's a bug in the C++ front end, at least as regards the initializer. It's expressly documented that this is allowed in initializers. See also my note in <http://gcc.gnu.org/ml/gcc-patches/2008-10/msg01061.html> about how what should be allowed with __builtin_constant_p goes beyond what I put in my formal models of desired constant expression semantics for GCC in 2004. If you get this wrong for C then GCC will fail to bootstrap, as it's part of the GNU C semantics GCC relies on when being built with GCC.
Ok, so this is a special case when __builtin_constant_p is immediately the operand of "?:"? Do you allow things like __builtin_constant_p(...)+0 as the operand?
Subject: Re: __builtin_constant_p(t) ? t : 1 is not considered a constant integer expression On Sat, 6 Dec 2008, sabre at nondot dot org wrote: > Ok, so this is a special case when __builtin_constant_p is immediately the > operand of "?:"? Do you allow things like __builtin_constant_p(...)+0 as the > operand? Yes, this is a (documented) special case required to be compatible with existing GNU C code. __builtin_constant_p(...)+0 is not allowed as the condition; the bcp_call property propagates though parentheses and through being an operand of __builtin_choose_expr, but not otherwise. For example, ((__builtin_choose_expr(1, (__builtin_constant_p(...)), 1))) has the bcp_call property. I think the description in my formal model is right for how this property propagates, except it leaves it unclear what the property is for the result of a conditional expression where both the condition and the selected half of the expression have the bcp_call property. In that case, I don't think the conditional expression should have the property, and it doesn't in the implementation on c-4_5-branch. The formal model seems unclear here, but I think it should be interpreted as the bcp_call property being lost through the implicit conversion of the ?: operands to a common type. What I didn't realise when writing the formal model is that the conditional expression, with a bcp_call condition, must be treated like the *folded* version of the selected half of the expression, since __builtin_constant_p tests constancy of the folded version. If __builtin_constant_p accepts (0 && foo()) as constant then this needs to be accepted in the selected half of the initializer. And for optimal handling of the use case for this use of __builtin_constant_p (in particular, detecting constant insn conditions when building GCC), such expressions as (0 && foo()) should be accepted as constant by __builtin_constant_p (0 may have been a macro expansion of TARGET_64BIT or similar).
That is a lot more clear. Thank you for the explanation Joseph! I agree with you that if you want this to be acceptable that the folded version of the operand is really what is interesting. That seems much trickier to model though.
Here are the testcases I checked in with the clang implementation of this if you're interested: // __builtin_constant_p as the condition of ?: allows arbitrary foldable // constants to be transmogrified into i-c-e's. char b[__builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+2.0) : -1]; struct c { int a : ( // expected-error {{expression is not an integer constant expression}} __builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+ expr // expected-note {{subexpression not valid in an integer constant expression}} ) : -1); };
oh, that also has 'int expr;' at global scope earlier.
Subject: Re: __builtin_constant_p(t) ? t : 1 is not considered a constant integer expression I also added more __builtin_constant_p tests (gcc.dg/bconstp-[34].c) to c-4_5-branch, following this discussion, to verify more of the model for how __builtin_constant_p works in constant expressions. In general the constant expressions tests there (both those added there, and the previously existing constant expressions / overflow diagnostics tests, most of which have had XFAILs removed on the branch) reflect my interpretation for the GNU C language of both the standard constant expressions rules where unclear and of how the rules should be applied to new language features in GNU C that aren't in ISO C.
The test case still fails with 4.5.3, but compiles successfully with 4.9.3 and later. Tests similar to the one in comment #0 that exercise this are in the test suite (two were were added in r230453). I'm resolving this bug as Fixed.
This bug should be reopened. The following test still fails: int t = 1; enum { N = __builtin_constant_p(t) ? t : 1 }; zira:~> g++-6 --version g++-6 (Debian 6.2.1-5) 6.2.1 20161124 [...] zira:~> g++-6 tst.c -c -std=c++98 tst.c:2:38: error: ‘t’ cannot appear in a constant-expression enum { N = __builtin_constant_p(t) ? t : 1 }; (I doubt this is a Debian-specific bug.)
Ditto in C with _Static_assert, as soon as optimizations are enabled: void f (void) { int t = 1; _Static_assert (__builtin_constant_p (t) ? t : 1, "err"); } $ gcc-6 -c fail.c $ gcc-6 -c fail.c -O fail.c: In function ‘f’: fail.c:4:48: error: expression in static assertion is not constant _Static_assert (__builtin_constant_p (t) ? t : 1, "err"); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~