Files
glibc/assert/test-assert-c++-variadic.cc
T
Jonathan WakelyandTomasz Kamiński ea37298b65 assert: Support assert as variadic macro for C++26 [PR27276]
C++26 changes assert into a variadic macro to support using
assignment-expressions that would be interpreted as multiple macro
arguments, in particular one containing:
* template parameter lists: func<int, float>()
* calls to overloaded operator[] that accepts multiple arguments: arr[1, 2]
  this is C++23 feature, see libstdc++ PR/119855 [1]
* lambdas with explicit captures: [x, y] { ... }

The new expansion in form:
  (__VA_ARGS__) ? void (1 ? 1 : bool (__VA_ARGS__))
                : __assert_fail (...)
Has the following properties:
* Use of (__VA_ARGS__) ? ... : ..., requires that __VA_ARGS__
  is contextually convertible to bool. This means that enumerators
  of scoped enumeration are no longer accepted (they are only
  explicitly convertible). Thus this patch address the glibc PR/27276 [2].
* Nested ternary 1 ? 1 : bool (__VA_ARGS__) guarantees that
  expression expanded from __VA_ARGS__ is not evaluated twice.
  This is used instead of unevaluated context (like sizeof...)
  to support C++ expressions that are not allowed in unevaluated
  context (lambdas until C++20, co_await, co_yield).
* bool (__VA_ARGS__) is ill-formed if __VA_ARGS__ expands to
  multiple arguments: assert(1, 2)
* bool (__VA_ARGS__) also triggers warnings when __VA_ARGS__
  expands to x = 1: assert(x = 1)

To guarantee that the code snippets from assert/test-assert-c++-variadic.cc,
are actually checked for validity, we need to compile this test in C++26
(-std=c++26) mode. To achieve that, this patch compiles the file with
test-config-cxxflags-stdcxx26 variable as additional flag, that is set to
-std=c++26 if $(TEST_CXX) executable supports that flag, and empty otherwise.

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119855
[2] https://sourceware.org/bugzilla/show_bug.cgi?id=27276

Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-03-02 14:24:17 -03:00

116 lines
2.1 KiB
C++

/* Test assert as a variadic macro for C++ code snippets.
Copyright The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This test requires C++26, and is compiled with -std=c++26
if GCC version supports that, and no additional options
otherwise. */
#if defined __cplusplus && __cplusplus > 202302L
#undef NDEBUG
#include <assert.h>
template <typename T1, typename T2>
bool
foo ()
{ return true; }
struct C
{
C (int p, int r) : x (p + r) {}
int x;
};
int
func ()
{
return 1;
}
static void
test_enabled ()
{
{
assert (foo <int, float> ());
}
{
assert (C {1, 2}.x > 0);
}
{
int x = 10, y = 20;
assert ([x, y] { return x < y; } ());
}
{
/* Ill-formed, not an assigment expression. */
// assert (func (), func ());
assert ((func (), func ()));
}
}
template <typename Ts>
constexpr bool
assert_works ()
{
return requires (Ts ts) {
assert (ts);
};
}
enum OE { oe };
enum TE : int { te };
enum class SE : int { se };
static_assert ( assert_works <OE> ());
static_assert ( assert_works <TE> ());
static_assert (!assert_works <SE> ());
#define NDEBUG
#include <assert.h>
static void
test_disabled ()
{
/* Assert is variadic, but ignores arguments */
assert(1, 2);
assert(+, 1, -, 2, *, 30);
}
static int
do_test ()
{
test_enabled ();
test_disabled ();
return 0;
}
#else
#include <support/test-driver.h>
static int
do_test ()
{
return EXIT_UNSUPPORTED;
}
#endif
#include <support/test-driver.c>