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.
I thought this is documented somewhere but __builtin_choose_expr only really accept constant literals and not constexprs.
(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.
(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."
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.
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).
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.
Not a bug.