On Mon, 30 Mar 2026 23:07:01 -0700
Kees Cook <[email protected]> wrote:

> On Mon, Mar 30, 2026 at 02:20:03PM +0100, [email protected] wrote:
> > From: David Laight <[email protected]>
> > 
> > The __builtin_choose_expr() doesn't gain you anything, replace with
> > a simple ?: operator.
> > Then __is_constexpr() can then be replaced with __builtin_constant_p().
> > This still works for static initialisers - the expression can contain
> > a function call - provided it isn't actually called.  
> 
> But __is_constexpr() != __builtin_constant_p(). I will go find the
> horrible examples of why this, too, needed so much careful construction.
> 

I know all about that.
Loosely __is_constexpr() requires that the initial compilation pass
sees something that is constant, whereas __builtin_constant_p() can
initially say 'not sure' and then a later compilation pass (eg after
function inlining) can determine that it is true after all.
There are a few places where C requires an 'integer constant expression',
otherwise __builtin_constant_p() is good enough.

__builtin_choose_expr() is also pretty much exactly the same as ?:
except that the types of the two expressions can differ.
In particular both bits of code have to compile without warnings
and have to be valid where it is used.

Note that you can have a function call in a static initialiser but not a
statement expression ({...}). C requires the expression be constant
- so the function can't be called, but it is syntactically valid.
So if you have a ({...}) in the unselected code of a __builtin_choose_expr()
you can't use it for a static initialiser.

Once you've relaxed the __builtin_choose_expr() to ?: you can relax
the test to __builtin_constant_p().
That is then (usually) true for constant values passed into inline functions.
I think I found a few cases where it made a difference.

        David



Reply via email to