Eric Blake wrote: > We could, however, add use of the __extension__ keyword anywhere we > use ({...}) in public macros
That's a good suggestion, thanks. Implemented through the patch below. In fact, use of the __extension__ keyword not only silences the -Wpedantic warning. It also allows to use the statement-as-expression extension when __STRICT_ANSI__ is defined, i.e. when a -std option is used that denotes a C standard without GNU extensions [1]. See: $ cat foo.c int foo (int x) { return __extension__ ({ int y = x * x; y * y; }); } $ gcc -std=c90 -Wpedantic -S foo.c $ gcc -std=c99 -Wpedantic -S foo.c $ gcc -std=c11 -Wpedantic -S foo.c $ gcc -std=c17 -Wpedantic -S foo.c $ gcc -std=c2x -Wpedantic -S foo.c This works in the same way with clang, even in such old versions as 2.8: $ clang -std=c90 -S foo.c $ clang -std=c99 -S foo.c as well as in new versions, e.g. 16.0.0: $ clang -std=c90 -S -Wall -Wpedantic foo.c $ clang -std=c99 -S -Wall -Wpedantic foo.c $ clang -std=c11 -S -Wall -Wpedantic foo.c $ clang -std=c17 -S -Wall -Wpedantic foo.c $ clang -std=c2x -S -Wall -Wpedantic foo.c > along with suitable magic to #define > __extension__ to empty on non-gcc compilers This is not needed. We use ({...}) only with GNU C (>= 2.8) and clang. These compilers support __extension__. Note also that the compiler built-ins __builtin_constant_p and __builtin_mul_overflow are available in strict ISO C mode [2]. [1] https://gcc.gnu.org/onlinedocs/gcc-13.2.0/cpp/Common-Predefined-Macros.html [2] https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html 2023-09-04 Bruno Haible <br...@clisp.org> Use statement-expressions without warnings, even in strict ISO C mode. Suggested by Eric Blake <ebl...@redhat.com> in <https://lists.gnu.org/archive/html/bug-gnulib/2023-09/msg00025.html>. * lib/error.in.h (__gl_error_call): Use the variant with obvious control flow also with clang. Use '__extension__' to avoid -Wpedantic warnings. * lib/math.in.h (gl_signbitf, gl_signbitd, gl_signbitl): Define as macros even when __STRICT_ANSI__ is defined. But use '__extension__' to avoid -Wpedantic warnings. * lib/setenv.c (KNOWN_VALUE): Use '__extension__' to avoid -Wpedantic warnings. * lib/xalloc-oversized.h (xalloc_oversized): Use optimized variant even when __STRICT_ANSI__ is defined. But use '__extension__' to avoid -Wpedantic warnings. diff --git a/lib/error.in.h b/lib/error.in.h index 94477fde08..61f98c5216 100644 --- a/lib/error.in.h +++ b/lib/error.in.h @@ -53,7 +53,7 @@ /* Helper macro for supporting the compiler's control flow analysis better. It evaluates its arguments only once. Test case: Compile copy-file.c with "gcc -Wimplicit-fallthrough". */ -#ifdef __GNUC__ +#if defined __GNUC__ || defined __clang__ /* Use 'unreachable' to tell the compiler when the function call does not return. */ # define __gl_error_call1(function, status, ...) \ @@ -66,11 +66,12 @@ would trigger a -Wimplicit-fallthrough warning even when STATUS is != 0, when not optimizing. This causes STATUS to be evaluated twice, but that's OK since it does not have side effects. */ -# define __gl_error_call(function, status, ...) \ - (__builtin_constant_p (status) \ - ? __gl_error_call1 (function, status, __VA_ARGS__) \ - : ({ \ - int const __errstatus = status; \ +# define __gl_error_call(function, status, ...) \ + (__builtin_constant_p (status) \ + ? __gl_error_call1 (function, status, __VA_ARGS__) \ + : __extension__ \ + ({ \ + int const __errstatus = status; \ __gl_error_call1 (function, __errstatus, __VA_ARGS__); \ })) #else diff --git a/lib/math.in.h b/lib/math.in.h index 117bc993b5..75d5013cf1 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2695,12 +2695,13 @@ _GL_WARN_REAL_FLOATING_DECL (isnan); _GL_EXTERN_C int gl_signbitf (float arg); _GL_EXTERN_C int gl_signbitd (double arg); _GL_EXTERN_C int gl_signbitl (long double arg); -# if (__GNUC__ >= 2 || defined __clang__) && !defined __STRICT_ANSI__ +# if __GNUC__ >= 2 || defined __clang__ # define _GL_NUM_UINT_WORDS(type) \ ((sizeof (type) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) # if defined FLT_SIGNBIT_WORD && defined FLT_SIGNBIT_BIT && !defined gl_signbitf # define gl_signbitf_OPTIMIZED_MACRO # define gl_signbitf(arg) \ + __extension__ \ ({ union { float _value; \ unsigned int _word[_GL_NUM_UINT_WORDS (float)]; \ } _m; \ @@ -2711,6 +2712,7 @@ _GL_EXTERN_C int gl_signbitl (long double arg); # if defined DBL_SIGNBIT_WORD && defined DBL_SIGNBIT_BIT && !defined gl_signbitd # define gl_signbitd_OPTIMIZED_MACRO # define gl_signbitd(arg) \ + __extension__ \ ({ union { double _value; \ unsigned int _word[_GL_NUM_UINT_WORDS (double)]; \ } _m; \ @@ -2721,6 +2723,7 @@ _GL_EXTERN_C int gl_signbitl (long double arg); # if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT && !defined gl_signbitl # define gl_signbitl_OPTIMIZED_MACRO # define gl_signbitl(arg) \ + __extension__ \ ({ union { long double _value; \ unsigned int _word[_GL_NUM_UINT_WORDS (long double)]; \ } _m; \ diff --git a/lib/setenv.c b/lib/setenv.c index 22b12fd018..706a032a49 100644 --- a/lib/setenv.c +++ b/lib/setenv.c @@ -82,6 +82,7 @@ typedef int (*compar_fn_t) (const void *, const void *); static void *known_values; # define KNOWN_VALUE(Str) \ + __extension__ \ ({ \ void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ value != NULL ? *(char **) value : NULL; \ diff --git a/lib/xalloc-oversized.h b/lib/xalloc-oversized.h index 5dbdfb5506..483bd11796 100644 --- a/lib/xalloc-oversized.h +++ b/lib/xalloc-oversized.h @@ -48,13 +48,13 @@ #if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX # define xalloc_oversized(n, s) \ __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1) -#elif (5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__ \ - && PTRDIFF_MAX < SIZE_MAX) +#elif 5 <= __GNUC__ && !defined __ICC && PTRDIFF_MAX < SIZE_MAX # define xalloc_oversized(n, s) \ (__builtin_constant_p (n) && __builtin_constant_p (s) \ ? __xalloc_oversized (n, s) \ - : ({ ptrdiff_t __xalloc_count; \ - __builtin_mul_overflow (n, s, &__xalloc_count); })) + : __extension__ \ + ({ ptrdiff_t __xalloc_count; \ + __builtin_mul_overflow (n, s, &__xalloc_count); })) /* Other compilers use integer division; this may be slower but is more portable. */