Bug 66963 - __builtin_constant_p and __builtin_choose_expr do not agree on what is a constexpr with -O2
Summary: __builtin_constant_p and __builtin_choose_expr do not agree on what is a cons...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 5.1.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-07-21 19:15 UTC by Nicolai Stange
Modified: 2021-09-29 08:25 UTC (History)
0 users

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 Nicolai Stange 2015-07-21 19:15:07 UTC
The first argument to __builtin_choose_expr() must be a constant expression.

However, at -O2, the following does not work:

  int foo (void)
  {
    const int a = 0;
    return __builtin_choose_expr(__builtin_choose_expr(__builtin_constant_p(a + 1), a + 1, 0),
                                 0, 0);
  }

test.c: In function ‘foo’:
test.c:4:10: error: first argument to ‘__builtin_choose_expr’ not a constant
   return __builtin_choose_expr(__builtin_choose_expr(__builtin_constant_p(a + 1), a + 1, 0),
          ^

Obviously, __builtin_constant_p() recognizes 'a+1' as being constant-foldable and returns nonzero. This makes the inner __builtin_choose_expr() select its second argument, i.e. 'a+1'. The outer __builtin_choose_expr() in turn refuses to accept that 'a+1' as a constant expression for its condition argument because it does not recognize it as a constexpr.


As a workaround, you can wrap the 'a+1' in a __builtin_expect() which seems to apply constant-folding in the same way the __builtin_constant_p() does:
  __builtin_choose_expr(__builtin_choose_expr(__builtin_constant_p(a + 1),
                                              __builtin_expect(a + 1, 1), 0),
                        0, 0);

Thus, it looks like constant folding is not applied to __builtin_choose_expr()'s first argument.
Comment 1 Andrew Pinski 2015-07-21 23:25:02 UTC
I thought this is documented somewhere but __builtin_choose_expr only really accept constant literals and not constexprs.
Comment 2 Andrew Pinski 2015-07-21 23:26:23 UTC
(In reply to Andrew Pinski from comment #1)
> I thought this is documented somewhere but __builtin_choose_expr only really
> accept constant literals and not constexprs.

And the main reason is the __builtin_choose_expr chooses the expression before semantics analysis happens so the first argument needs to be a constant literal.
Comment 3 Nicolai Stange 2015-07-21 23:35:14 UTC
(In reply to Andrew Pinski from comment #1)
> I thought this is documented somewhere but __builtin_choose_expr only really
> accept constant literals and not constexprs.

https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
explicitly mentions integer constant expressions though. Quote: "This built-in function returns exp1 if const_exp, which is an integer constant expression, is nonzero."
Comment 4 Nicolai Stange 2015-07-21 23:37:56 UTC
Sorry, misunderstanding at my side. You probably did not mean constexprs in the sense of C99, 6.6, but constexprs in the sense of constant folded expressions.
Comment 5 jsm-csl@polyomino.org.uk 2015-07-28 22:56:57 UTC
This is by design.  __builtin_choose_expr requires an integer constant 
expression which must be evaluated before the type of the result can be 
known; __builtin_constant_p is for optimization and evaluates, much later, 
whether something is folded to a constant (including constant arguments to 
inline functions).
Comment 6 Nicolai Stange 2015-07-29 06:35:52 UTC
Thank you for your clarifications, Andrew and Joseph.

As far as I am concerned, this bug can be marked as resolved/rejected/whatever you like.
Comment 7 Richard Biener 2015-07-29 07:30:36 UTC
Not a bug.