* lib/stdcountof.in.h (countof, _gl_verify_is_array): Allow arguments that are compound literals, and thus appear as multiple arguments to a C macro. * tests/test-stdcountof-h.c: Test for this. --- ChangeLog | 6 ++++++ lib/stdcountof.in.h | 21 +++++++++++---------- tests/test-stdcountof-h.c | 1 + 3 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/ChangeLog b/ChangeLog index f3a5d317fd..1dd55d1ade 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2025-11-06 Paul Eggert <[email protected]> + stdcountof-h: allow compound literal args + * lib/stdcountof.in.h (countof, _gl_verify_is_array): + Allow arguments that are compound literals, and thus + appear as multiple arguments to a C macro. + * tests/test-stdcountof-h.c: Test for this. + stdio-windows: fix <stdarg.h> include position Problem reported by Andy Moreton in: https://lists.gnu.org/r/bug-gnulib/2025-11/msg00059.html diff --git a/lib/stdcountof.in.h b/lib/stdcountof.in.h index 6e602b4a9f..1fc06401be 100644 --- a/lib/stdcountof.in.h +++ b/lib/stdcountof.in.h @@ -47,8 +47,9 @@ Attempts to produce an error if A is a pointer, e.g. in void func (int a[10]) { ... } */ -#define countof(a) \ - ((size_t) (sizeof (a) / sizeof ((a)[0]) + 0 * _gl_verify_is_array (a))) +#define countof(...) \ + ((size_t) (sizeof (__VA_ARGS__) / sizeof (__VA_ARGS__)[0] \ + + 0 * _gl_verify_is_array (__VA_ARGS__))) /* Attempts to verify that A is an array. */ #if defined __cplusplus @@ -75,8 +76,8 @@ template <typename T, size_t N> /* String literals. */ template <typename T, size_t N> struct _gl_array_type_test<T const (&)[N]> { static const int is_array = 1; }; -# define _gl_verify_is_array(a) \ - sizeof (_gl_verify_type<_gl_array_type_test<decltype(a)>::is_array>) +# define _gl_verify_is_array(...) \ + sizeof (_gl_verify_type<_gl_array_type_test<decltype(__VA_ARGS__)>::is_array>) # else /* Use template argument deduction. Use sizeof to get a constant expression from an unknown type. @@ -93,22 +94,22 @@ template <typename T, size_t N> /* The T& parameter is essential here: it prevents decay (array-to-pointer conversion). */ template <typename T> _gl_array_type_test<T> _gl_array_type_test_helper(T&); -# define _gl_verify_is_array(a) \ - sizeof (_gl_verify_type<(sizeof (_gl_array_type_test_helper(a)) < sizeof (double) ? 1 : -1)>) +# define _gl_verify_is_array(...) \ + sizeof (_gl_verify_type<(sizeof (_gl_array_type_test_helper(__VA_ARGS__)) < sizeof (double) ? 1 : -1)>) # endif # else /* The compiler does not have the necessary functionality. */ -# define _gl_verify_is_array(a) 0 +# define _gl_verify_is_array(...) 0 # endif #else /* In C, we can use typeof and __builtin_types_compatible_p. */ /* Work around clang bug <https://github.com/llvm/llvm-project/issues/143284>. */ # if _GL_GNUC_PREREQ (3, 1) && ! defined __clang__ /* || defined __clang__ */ -# define _gl_verify_is_array(a) \ - sizeof (struct { unsigned int _gl_verify_error_if_negative : __builtin_types_compatible_p (typeof (a), typeof (&*(a))) ? -1 : 1; }) +# define _gl_verify_is_array(...) \ + sizeof (struct { unsigned int _gl_verify_error_if_negative : __builtin_types_compatible_p (typeof (__VA_ARGS__), typeof (&*(__VA_ARGS__))) ? -1 : 1; }) # else /* The compiler does not have the necessary built-ins. */ -# define _gl_verify_is_array(a) 0 +# define _gl_verify_is_array(...) 0 # endif #endif diff --git a/tests/test-stdcountof-h.c b/tests/test-stdcountof-h.c index 42f2f82537..4e88d5bf66 100644 --- a/tests/test-stdcountof-h.c +++ b/tests/test-stdcountof-h.c @@ -80,6 +80,7 @@ test_func (int parameter[3]) { extern int a, b, c; + ASSERT (countof ((int[]) { a, b, c }) == 3); ASSERT (countof (((int[]) { a, b, c })) == 3); } -- 2.51.0
