[PATCH] libstdc++: Make VERIFY a variadic macro
Tomasz Kaminski
tkaminsk@redhat.com
Mon Jul 7 15:14:54 GMT 2025
On Wed, Jul 2, 2025 at 12:31 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> This defines the testsuite assertion macro VERIFY so that it allows
> un-parenthesized expressions containing commas. This matches how assert
> is defined in C++26, following the approval of P2264R7.
>
> The primary motivation is to allow expressions that the preprocessor
> splits into multiple arguments, e.g.
> VERIFY( vec == std::vector<int>{1,2,3,4} );
>
> To achieve this, VERIFY is redefined as a variadic macro and then the
> arguments are grouped together again through the use of __VA_ARGS__.
>
> The implementation is complex due to the following points:
>
> - The arguments __VA_ARGS__ are contextually-converted to bool, so that
> scoped enums and types that are not contextually convertible to bool
> cannot be used with VERIFY.
> - bool(__VA_ARGS__) is used so that multiple arguments (i.e. those which
> are separated by top-level commas) are ill-formed. Nested commas are
> allowed, but likely mistakes such as VERIFY( cond, "some string" ) are
> ill-formed.
> - The bool(__VA_ARGS__) expression needs to be unevaluated, so that we
> don't evaluate __VA_ARGS__ more than once. The simplest way to do that
> would be just sizeof bool(__VA_ARGS__), without parentheses to avoid a
> vexing parse for VERIFY(bool(i)). However that wouldn't work for e.g.
> VERIFY( []{ return true; }() ), because lambda expressions are not
> allowed in unevaluated contexts until C++20. So we use another
> conditional expression with bool(__VA_ARGS__) as the unevaluated
> operand.
>
> libstdc++-v3/ChangeLog:
>
> * testsuite/util/testsuite_hooks.h (VERIFY): Define as variadic
> macro.
> * testsuite/ext/verify_neg.cc: New test.
> ---
>
> Tested powerpc64le-linux.
>
LGTM. I have followed the discussion on the LWG reflector on it.
>
> libstdc++-v3/testsuite/ext/verify_neg.cc | 28 +++++++++++++++++++
> libstdc++-v3/testsuite/util/testsuite_hooks.h | 17 +++++------
> 2 files changed, 35 insertions(+), 10 deletions(-)
> create mode 100644 libstdc++-v3/testsuite/ext/verify_neg.cc
>
> diff --git a/libstdc++-v3/testsuite/ext/verify_neg.cc
> b/libstdc++-v3/testsuite/ext/verify_neg.cc
> new file mode 100644
> index 000000000000..ce033741beeb
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/ext/verify_neg.cc
> @@ -0,0 +1,28 @@
> +// { dg-do compile { target c++11 } }
> +
> +#include <testsuite_hooks.h>
> +
> +struct X { explicit operator void*() const { return nullptr; } };
> +
> +void
> +test_VERIFY(int i)
> +{
> + // This should not be parsed as a function type bool(bool(i)):
> + VERIFY( bool(i) );
> +
> + // This should not produce warnings about lambda in unevaluated context:
> + VERIFY( []{ return 1; }() );
> +
> + // Only one expression allowed:
> + VERIFY(1, 2); // { dg-error "in expansion of macro" }
> + // { dg-error "compound expression in functional cast" "" { target
> *-*-* } 0 }
> +
> + // A scoped enum is not contextually convertible to bool:
> + enum class E { E0 };
> + VERIFY( E::E0 ); // { dg-error "could not convert" }
> +
> + // explicit conversion to void* is not contextually convertible to bool:
> + X x;
> + VERIFY( x ); // { dg-error "in expansion of macro" }
> + // { dg-error "invalid cast .* to type 'bool'" "" { target *-*-* } 0 }
> +}
> diff --git a/libstdc++-v3/testsuite/util/testsuite_hooks.h
> b/libstdc++-v3/testsuite/util/testsuite_hooks.h
> index faa01ba6abd8..bf34fd121c1b 100644
> --- a/libstdc++-v3/testsuite/util/testsuite_hooks.h
> +++ b/libstdc++-v3/testsuite/util/testsuite_hooks.h
> @@ -58,16 +58,13 @@
> # define _VERIFY_PRINT(S, F, L, P, C) __builtin_printf(S, F, L, P, C)
> #endif
>
> -#define VERIFY(fn) \
> - do \
> - { \
> - if (! (fn))
> \
> - {
> \
> - _VERIFY_PRINT("%s:%d: %s: Assertion '%s' failed.\n", \
> - __FILE__, __LINE__, __PRETTY_FUNCTION__, #fn); \
> - __builtin_abort(); \
> - }
> \
> - } while (false)
> +#define VERIFY(...) \
> + ((void)((__VA_ARGS__) \
> + ? (void)(true ? true : bool(__VA_ARGS__)) \
> + : (_VERIFY_PRINT("%s:%d: %s: Assertion '%s' failed.\n", \
> + __FILE__, __LINE__, __PRETTY_FUNCTION__, \
> + #__VA_ARGS__), \
> + __builtin_abort())))
>
> #ifdef _GLIBCXX_HAVE_UNISTD_H
> # include <unistd.h>
> --
> 2.50.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250707/2699b213/attachment-0001.htm>
More information about the Libstdc++
mailing list