[PATCH] assert: Support assert as variadic macro for C++26 [PR27276]

Florian Weimer fweimer@redhat.com
Thu Feb 5 16:13:06 GMT 2026


* Jonathan Wakely:

> On Thu, 5 Feb 2026 at 15:48, Jonathan Wakely <jwakely@redhat.com> wrote:
>>
>> On Thu, 5 Feb 2026 at 15:40, Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>> >
>> >
>> >
>> > On Thu, Feb 5, 2026 at 4:36 PM Florian Weimer <fweimer@redhat.com> wrote:
>> >>
>> >> * Tomasz Kamiński:
>> >>
>> >> > +#  if __ASSERT_VARIADIC
>> >> > +#    define assert(...)                                                      \
>> >> > +     ((__VA_ARGS__)                                                  \
>> >> > +      ? (void)(1 ? 1 : bool(__VA_ARGS__))                            \
>> >> > +      : __assert_fail (#__VA_ARGS__, __ASSERT_FILE, __ASSERT_LINE,   \
>> >> > +                       __ASSERT_FUNCTION))
>> >>
>> >> Doesn't this evaluate __VA_ARGS__ multiple times?
>> >
>> > I got the same question initially when I saw this solution, but
>> > the second bool(__VA_ARGS) is in the false branch of the ternary:
>> > 1 ? 1 : bool(__VA_ARGS__)
>> > So it is never evaluated.
>>
>> Right, it's never evaluated, it's only there to enforce that
>> __VA_ARGS__ expands to a single expression, because bool(x,y) is
>> ill-formed.
>
> Maybe it needs a comment explaining the logic, and saying "Be careful
> when touching this, every piece of it is load-bearing!" ;-)
>
> The key pieces are that this relies on the "contextually converted to
> bool" rule <https://wg21.link/conv.general#4>
>
> (__VA_ARGS__) ? expr : __assert_fail(...);
>
> This is a "weaker" form of conversion than casting to bool, and so
> prevents scoped enum types from being asserted on (they aren't
> convertible to integers, so they shouldn't be implicitly converted to
> 'true;' or 'false' in assertions).
>
> And as explained above, the (void)(1 ? 1 : bool(__VA_ARGS__)) part has
> no side effects but ensures that assert(x, y) is ill-formed, at least
> when NDEBUG is not defined.

The problem about the first (__VA_ARGS__) is that because it's extra
parentheses, it suppresses the warning we want for:

  assert (x = 1);

The bool(__VA_ARGS__) part still warns.  So that part has not one, but
two functions.  I think I we ended up with static_cast<bool> (…) because
there is no such warning for (bool) (…), and I maybe I thought that was
too close to bool (…).

Thanks,
Florian



More information about the Libc-alpha mailing list