On Wed, Jul 2, 2025 at 12:31 PM Jonathan Wakely <jwak...@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 > >