tests := \
test-assert \
test-assert-2 \
+ test-assert-c++-variadic \
test-assert-c99 \
test-assert-gnu99 \
test-assert-perr \
CFLAGS-test-assert-gnu99.c += -std=gnu99
ifeq ($(have-cxx-thread_local),yes)
+CFLAGS-test-assert-c++-variadic.o = $(test-config-cxxflags-stdcxx26)
+LDLIBS-test-assert-c++-variadic = -lstdc++
CFLAGS-tst-assert-c++.o = -std=c++11
LDLIBS-tst-assert-c++ = -lstdc++
CFLAGS-tst-assert-g++.o = -std=gnu++11
LDLIBS-tst-assert-g++ = -lstdc++
else
tests-unsupported += \
+ test-assert-c++-variadic \
tst-assert-c++ \
tst-assert-g++ \
# tests-unsupported
comma in the initializer list, can be passed to assert. This
depends on support for variadic macros (added in C99 and GCC 2.95),
and on support for _Bool (added in C99 and GCC 3.0) in order to
- validate that only a single expression is passed as an argument,
- and is currently implemented only for C. */
-#if (__GLIBC_USE (ISOC23) \
- && (defined __GNUC__ \
- ? __GNUC_PREREQ (3, 0) \
- : defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) \
- && !defined __cplusplus)
+ validate that only a single expression is passed as an argument. */
+#if ((__GLIBC_USE (ISOC23) \
+ && (defined __GNUC__ \
+ ? __GNUC_PREREQ (3, 0) \
+ : defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) \
+ || (defined __cplusplus && __cplusplus > 202302L))
# define __ASSERT_VARIADIC 1
#else
# define __ASSERT_VARIADIC 0
__THROW __attribute__ ((__noreturn__)) __COLD;
-# 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. */
# define __ASSERT_FILE __FILE__
# define __ASSERT_LINE __LINE__
# endif
-# define assert(expr) \
+# if __ASSERT_VARIADIC
+/* The first test of __VA_ARGS__ evaluates it without converting scoped
+ enumeration values to bool, and the second test checks that it is a
+ single expression without evaluating it. */
+# define assert(...) \
+ ((__VA_ARGS__) \
+ ? void (1 ? 1 : bool (__VA_ARGS__)) \
+ : __assert_fail (#__VA_ARGS__, __ASSERT_FILE, __ASSERT_LINE, \
+ __ASSERT_FUNCTION))
+# else
+# define assert(expr) \
(static_cast <bool> (expr) \
? void (0) \
: __assert_fail (#expr, __ASSERT_FILE, __ASSERT_LINE, \
__ASSERT_FUNCTION))
+# endif
# elif !defined __GNUC__ || defined __STRICT_ANSI__
# if __ASSERT_VARIADIC
# define assert(...) \
--- /dev/null
+/* 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>
#include <assert.h>
#if __GNUC_PREREQ (5, 0)
+template <typename> struct is_void { static const bool value = false; };
+template <> struct is_void <void> { static const bool value = true; };
+
+static_assert(is_void <decltype (assert (""))>::value, "type is void");
+
/* The C++ standard requires that if the assert argument is a constant
subexpression, then the assert itself is one, too. */
constexpr int
template <class T> bool operator!= (T) const; /* No definition. */
};
+/* Scoped enumerations are not contextually convertible to bool. */
+enum class E { e1 = 1 };
+
+int&
+preincrement (int& i)
+{
+ return ++i;
+}
+
static int
do_test ()
{
assert (value);
}
+ {
+ assert ([] { return true; } ());
+ }
+
+ {
+ assert (bool (E::e1));
+ /* Ill-formed, E::e1 is not contextually convertible to bool. */
+ // assert (E::e1);
+ }
+
+ {
+ int i = 0;
+ assert (preincrement (i) > 0);
+ if (i != 1)
+ return 1;
+ }
+
return 0;
}
+#define NDEBUG
+#include <assert.h>
+
+static_assert(is_void <decltype (assert (""))>::value, "type is void with NDEBUG");
+
#else
#include <support/test-driver.h>
config_vars="$config_vars
test-config-cxxflags-finput-charset-ascii = $libc_cv_test_cxxflags_finput_charset_ascii"
+
+
+saved_CXX="$CXX"
+CXX="$TEST_CXX"
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking $CXX -std=c++26 in testing" >&5
+printf %s "checking $CXX -std=c++26 in testing... " >&6; }
+if test ${libc_cv_test_cxxflags_stdcxx26+y}
+then :
+ printf %s "(cached) " >&6
+else case e in #(
+ e) if { ac_try='${CXX-c++} -Werror -std=c++26 -xc++ /dev/null -S -o /dev/null'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then :
+ libc_cv_test_cxxflags_stdcxx26="-std=c++26"
+else case e in #(
+ e) libc_cv_test_cxxflags_stdcxx26=
+ ;;
+esac
+fi ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_cxxflags_stdcxx26" >&5
+printf "%s\n" "$libc_cv_test_cxxflags_stdcxx26" >&6; }
+
+CXX="$saved_CXX"
+
+
+config_vars="$config_vars
+test-config-cxxflags-stdcxx26 = $libc_cv_test_cxxflags_stdcxx26"
+
conftest_code="
extern int not_exist (void);
LIBC_CONFIG_VAR(test-config-cxxflags-finput-charset-ascii,
$libc_cv_test_cxxflags_finput_charset_ascii)
+dnl Check if TEST_CXX supports -std=c++26.
+LIBC_TRY_TEST_CXX_OPTION([$CXX -std=c++26],
+ [-Werror -std=c++26],
+ libc_cv_test_cxxflags_stdcxx26,
+ [libc_cv_test_cxxflags_stdcxx26="-std=c++26"],
+ [libc_cv_test_cxxflags_stdcxx26=]
+)
+LIBC_CONFIG_VAR(test-config-cxxflags-stdcxx26,
+ $libc_cv_test_cxxflags_stdcxx26)
+
conftest_code="
extern int not_exist (void);