Bug 894515 - __builtin_constant_p() is broken, again
Summary: __builtin_constant_p() is broken, again
Keywords:
Status: CLOSED WONTFIX
Alias: None
Product: Fedora
Classification: Fedora
Component: gcc
Version: 18
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2013-01-11 23:03 UTC by Tom Lane
Modified: 2014-02-05 14:45 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2014-02-05 14:44:57 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Tom Lane 2013-01-11 23:03:08 UTC
Description of problem:
This test program:

static int xx;
static int foo[__builtin_constant_p(xx) ? 1 : 2];

int
main ()
{
 static int x; static int y[__builtin_constant_p(x) ? 0 : 1];
  ;
  return 0;
}

compiles fine without -O, but with -O you get

$ gcc -c -O bug.c
bug.c: In function 'main':
bug.c:7:27: error: storage size of 'y' isn't constant

Surely this is a bug.

Version-Release number of selected component (if applicable):
gcc-4.7.2-8.fc18.x86_64
same behavior on
gcc-4.6.3-2.fc16.x86_64

Additional info:
Bugzilla pointed me to bug #198849 ... did that come back?

Comment 1 Jakub Jelinek 2013-01-12 08:32:08 UTC
Why the again?  GCC has always behaved this way.
#198849 is a different thing, there __builtin_constant_p is used in the initializer, here it is used in the array size.
The standard condition when to fold __builtin_constant_p right away into zero (if it isn't a constant right away) is:
  if (TREE_SIDE_EFFECTS (arg)
      || AGGREGATE_TYPE_P (TREE_TYPE (arg))
      || POINTER_TYPE_P (TREE_TYPE (arg))
      || cfun == 0
      || folding_initializer)
    return integer_zero_node;
and
        if (!val && !optimize)
          val = integer_zero_node;
fold_initializer is true inside of the initializers (so #198849), cfun is NULL for variables outside of functions (so the first case in your testcase), and !optimize for -O0.  For everything else __builtin_constant_p folding is deferred to see if it is really a constant or not.  So e.g. in
void
foo ()
{
  static int x;
  int y[__builtin_constant_p (x) ? 1 : 2];
  bar (y);
}
the size of y array will be 4 bytes, because the compiler finds out that x is never modified and thus constant.  For
void
baz ()
{
  static int x;
  int y[__builtin_constant_p (x) ? 1 : 2];
  x++;
  bar (y);
}
the size of y array is 8 bytes, because x isn't constant.  Guess we could introduce some other flag or abuse folding_initializer for array bounds of static function local vars, but as this isn't a regression, it won't be changed even in the upcoming GCC 4.8.  So, just move that stuff outside of function scope if you want it to be folded right away?

Comment 2 Tom Lane 2013-01-12 17:38:34 UTC
Um ... I do not particularly care whether the compiler decides that __builtin_constant_p(x) is true or not.  I find it somewhat surprising that it would ever decide "yes", but that isn't the point.  The point is that it's unable to make up its mind.  Surely __builtin_constant_p(x) should have a compile-time-constant value, and therefore so should __builtin_constant_p(x) ? 0 : 1.  If it isn't a compile-time constant, that completely fails the principle of least astonishment.

The static-array-size example was just a convenient way of trying to show that it's failing to make up its mind.  The case that I'm actually concerned about is that I want to be sure that

__builtin_constant_p(expr) && (expr) ? foo : bar

is always simplified to the point where only foo or only bar is compiled, regardless of what expr is, and for that matter regardless of what the -O level is.  It's okay if the compiler makes a different choice at a higher -O level, but not okay if it can't make up its mind, and especially not okay if it generates code that would evaluate the expr.  (In the application I have in mind, this would result in a double-evaluation hazard for a macro argument.)  Your explanation does not fill me with confidence that this will work reliably.

Comment 3 Jakub Jelinek 2013-01-24 08:52:59 UTC
It depends on when is __builtin_constant_p evaluated as a compiler constant.  With a few exceptions (mentioned above), it is treated as a function call until late optimization passes, and only then folded into 0 or 1, so, unlike many other builtins, it can have different results based on optimizations performed (that is the whole point of it, see if after optimizations the value isn't a known constant).  But as it isn't a constant expression (unless the argument is known to be constant right away), using it in contexts where a constant expression is required is wrong.

Comment 4 Tom Lane 2013-01-24 15:24:35 UTC
(In reply to comment #3)
> ... it isn't a constant expression ...

That still seems pretty weird/unexpected though.

Looking closer, I think I'd misinterpreted the second example in the gcc manual's entry for __builtin_constant_p: I took it to say that such an expression would be a compile-time constant, but the example really only requires it to be a link-time constant.

Perhaps the manual entry could be clarified a bit?

Comment 6 Fedora End Of Life 2013-12-21 10:20:11 UTC
This message is a reminder that Fedora 18 is nearing its end of life.
Approximately 4 (four) weeks from now Fedora will stop maintaining
and issuing updates for Fedora 18. It is Fedora's policy to close all
bug reports from releases that are no longer maintained. At that time
this bug will be closed as WONTFIX if it remains open with a Fedora 
'version' of '18'.

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, simply change the 'version' 
to a later Fedora version prior to Fedora 18's end of life.

Thank you for reporting this issue and we are sorry that we may not be 
able to fix it before Fedora 18 is end of life. If you would still like 
to see this bug fixed and are able to reproduce it against a later version 
of Fedora, you are encouraged  change the 'version' to a later Fedora 
version prior to Fedora 18's end of life.

Although we aim to fix as many bugs as possible during every release's 
lifetime, sometimes those efforts are overtaken by events. Often a 
more recent Fedora release includes newer upstream software that fixes 
bugs or makes them obsolete.

Comment 7 Fedora End Of Life 2014-02-05 14:45:00 UTC
Fedora 18 changed to end-of-life (EOL) status on 2014-01-14. Fedora 18 is
no longer maintained, which means that it will not receive any further
security or bug fix updates. As a result we are closing this bug.

If you can reproduce this bug against a currently maintained version of
Fedora please feel free to reopen this bug against that version. If you
are unable to reopen this bug, please file a new report against the
current release. If you experience problems, please add a comment to this
bug.

Thank you for reporting this bug and we are sorry it could not be fixed.


Note You need to log in before you can comment on or make changes to this bug.