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

