Bug 38377 - __builtin_constant_p(t) ? t : 1 is not considered a constant integer expression
Summary: __builtin_constant_p(t) ? t : 1 is not considered a constant integer expression
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-12-02 21:58 UTC by Andrew Pinski
Modified: 2008-12-12 18:04 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrew Pinski 2008-12-02 21:58:50 UTC
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.
Comment 1 Chris Lattner 2008-12-06 18:42:59 UTC
This is a bug in the C front-end.  They need to use __builtin_choose_expr.
Comment 2 joseph@codesourcery.com 2008-12-06 19:09:08 UTC
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.

Comment 3 Chris Lattner 2008-12-06 21:31:58 UTC
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?
Comment 4 joseph@codesourcery.com 2008-12-06 22:53:25 UTC
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).

Comment 5 Chris Lattner 2008-12-12 06:42:51 UTC
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.
Comment 6 Chris Lattner 2008-12-12 18:02:33 UTC
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);
};
Comment 7 Chris Lattner 2008-12-12 18:04:50 UTC
oh, that also has 'int expr;' at global scope earlier.
Comment 8 joseph@codesourcery.com 2008-12-15 00:31:46 UTC
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.