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

Paul Eggert eggert@cs.ucla.edu
Mon Feb 16 21:59:08 GMT 2026


On 2026-02-09 03:27, Tomasz Kamiński wrote:

> Mainly for testing purposes we allow enabling/disabling variadic assert
> regardless of version of C or C++, by defining __ASSERT_VARIADIC to
> 1/0 respectively before inclusion of <assert>

I don't see the need for this extra complexity in this patch. People who 
want to do that sort of testing can do it in other ways. If there is a 
need, this part of the patch should be separated out into a different patch.

> +   Similary C++26 makes assert a variadic macro and allows expressions
> +   containing template argument lists, lambda captures, and many others
> +   that include commas, without requiring extra parentheses.

"Similarly" is misspelled. Plus, this comment talks about the wrong 
things. The key question (which the containing comment already answers 
for C) is which versions of the language standard and of GCC support the 
proposed implementation of variadic assert for C++. That's what the 
comment should talk about, not about which features of C++ can use the 
proposed patch. Or maybe it's simpler to just remove this comment 
entirely, if all versions of the standard and GCC support it.

> +#  if (__GLIBC_USE (ISOC23)						\
> +       && (defined __GNUC__						\
> +	   ? __GNUC_PREREQ (3, 0)					\
> +	   : defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)	\
> +       || (defined __cplusplus && __cplusplus >= 202302L))

Parenthesis are missing around the first disjunct.

More importantly, that "__cplusplus >= 202302L" looks wrong. This is a 
C++26 feature, right? Shouldn't it be "__cplusplus > 202302L"? Using 
">=" would cause g++ to not diagnose some invalid C++23 programs, even 
in pedantic mode.

> +#   define __ASSERT_VARIADIC 1
> +#  else
> +#    define __ASSERT_VARIADIC 0
> +#  endif
>   #endif
>   
>   /* void assert (int expression);
> @@ -108,7 +112,7 @@ extern void __assert (const char *__assertion, const char *__file, int __line)
>        __THROW __attribute__ ((__noreturn__)) __COLD;
>   __cplusplus >= 202302L
>   
> -# if __ASSERT_VARIADIC
> +# if __ASSERT_VARIADIC && !defined __cplusplus
>   /* This function is not defined and is not called outside of an
>      unevaluated sizeof, but serves to verify that the argument to
>      assert is a single expression.  */
> @@ -131,11 +135,19 @@ __END_DECLS
>   #   define __ASSERT_FILE __FILE__
>   #   define __ASSERT_LINE __LINE__
>   #  endif
> -#  define assert(expr)							\
> +#  if __ASSERT_VARIADIC
> +#    define assert(...)							\
> +     ((__VA_ARGS__)							\
> +      ? (void)(1 ? 1 : bool(__VA_ARGS__))				\
> +      : __assert_fail (#__VA_ARGS__, __ASSERT_FILE, __ASSERT_LINE,	\
> +                       __ASSERT_FUNCTION))

The proposed spacing near parens doesn't conform to the usual glibc style.

Why use '(void)(...) rather than 'void (...)' as the other arm does?

More importantly, can't we simplify things by avoiding one repetition of 
__VA_ARGS__ and doing something like the following instead?

  #define assert(...) \
    (bool (__VA_ARGS__) \
     ? void (0) \
     : __assert_fail (#__VA_ARGS__, __ASSERT_FILE, __ASSERT_LINE, \
                      __ASSERT_FUNCTION))



More information about the Libc-alpha mailing list