Using _Generic instead of casting should help includers of <intprops.h> to avoid suppression of -Wuseless-cast diagnostics. * lib/intprops-internal.h: Ignore -Wuseless-cast only if (__STDC_VERSION__ < 201112 && 14 <= __GNUC__). (_GL__GENERIC_BOGUS): Move definition up. * lib/intprops-internal.h (_GL_TYPE_SIGNED): * lib/intprops.h (TYPE_IS_INTEGER, TYPE_MINIMUM, TYPE_MAXIMUM): Use _Generic if this should work, to avoid the need for casts. * lib/intprops-internal.h (_GL_INT_NEGATE_OVERFLOW): * lib/intprops.h (_GL_ADD_OVERFLOW, _GL_SUBTRACT_OVERFLOW) (_GL_MULTIPLY_OVERFLOW): When _GL_HAS_BUILTIN_OVERFLOW_P, use _GL_INT_CONVERT to avoid the need for a cast. --- ChangeLog | 14 +++++++++++ lib/intprops-internal.h | 49 ++++++++++++++++++++++--------------- lib/intprops.h | 54 ++++++++++++++++++++++++++++++++--------- 3 files changed, 87 insertions(+), 30 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 76ae6d2a06..46fc6d5766 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2026-05-10 Paul Eggert <[email protected]> + intprops: ignore -Wuseless-cast less often + Using _Generic instead of casting should help includers of + <intprops.h> to avoid suppression of -Wuseless-cast diagnostics. + * lib/intprops-internal.h: Ignore -Wuseless-cast only + if (__STDC_VERSION__ < 201112 && 14 <= __GNUC__). + (_GL__GENERIC_BOGUS): Move definition up. + * lib/intprops-internal.h (_GL_TYPE_SIGNED): + * lib/intprops.h (TYPE_IS_INTEGER, TYPE_MINIMUM, TYPE_MAXIMUM): + Use _Generic if this should work, to avoid the need for casts. + * lib/intprops-internal.h (_GL_INT_NEGATE_OVERFLOW): + * lib/intprops.h (_GL_ADD_OVERFLOW, _GL_SUBTRACT_OVERFLOW) + (_GL_MULTIPLY_OVERFLOW): When _GL_HAS_BUILTIN_OVERFLOW_P, use + _GL_INT_CONVERT to avoid the need for a cast. + posixtm-tests: pacify -Wuseless-cast * tests/test-posixtm.c (main): Use compound literals, not casts. diff --git a/lib/intprops-internal.h b/lib/intprops-internal.h index a749cad1a4..f569d94a06 100644 --- a/lib/intprops-internal.h +++ b/lib/intprops-internal.h @@ -25,8 +25,20 @@ # pragma GCC diagnostic ignored "-Wtype-limits" #endif -/* This file uses many casts that might provoke -Wuseless-cast warnings. */ -#if 14 <= __GNUC__ +/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25764. See: + https://gcc.gnu.org/PR68193 + https://github.com/llvm/llvm-project/issues/25764 + For now, assume GCC < 14 and all Clang versions generate bogus + warnings for _Generic. This matters only for compilers that + lack relevant builtins. */ +#if (__GNUC__ && __GNUC__ < 14) || defined __clang__ +# define _GL__GENERIC_BOGUS 1 +#else +# define _GL__GENERIC_BOGUS 0 +#endif + +/* Suppress -Wuseless-cast for, e.g., gcc-14 -std=gnu99. */ +#if __STDC_VERSION__ < 201112 && 14 <= __GNUC__ # pragma GCC diagnostic ignored "-Wuseless-cast" #endif @@ -37,8 +49,19 @@ /* The extra casts in the following macros work around compiler bugs, e.g., in Cray C 5.0.3.0. */ -/* True if the real type T is signed. */ -#define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* True if the standard integer or standard real type T is signed. */ +#if __STDC_VERSION__ < 201112 || _GL__GENERIC_BOGUS +# define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +#else +/* Pacify -Wuseless-cast, but do not default to the simpler expression; + see <https://gcc.gnu.org/PR125261>. */ +# define _GL_TYPE_SIGNED(t) \ + (_Generic ((t) {0}, \ + bool: 0, char: CHAR_MIN < 0, signed char: 1, unsigned char: 0, \ + short int: 1, unsigned short int: 0, int: 1, unsigned int: 0, \ + long int: 1, unsigned long int: 0, long long int: 1, unsigned long long int: 0, \ + float: 1, double: 1, long double: 1)) +#endif /* Return 1 if the real expression E, after promotion, has a signed or floating type. Do not evaluate E. */ @@ -184,18 +207,6 @@ _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW) #endif -/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25764. See: - https://gcc.gnu.org/PR68193 - https://github.com/llvm/llvm-project/issues/25764 - For now, assume GCC < 14 and all Clang versions generate bogus - warnings for _Generic. This matters only for compilers that - lack relevant builtins. */ -#if (__GNUC__ && __GNUC__ < 14) || defined __clang__ -# define _GL__GENERIC_BOGUS 1 -#else -# define _GL__GENERIC_BOGUS 0 -#endif - /* Store the low-order bits of A <op> B into *R, where OP specifies the operation and OVERFLOW the overflow predicate. Return 1 if the result overflows. Arguments should not have side effects, @@ -309,15 +320,15 @@ ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) -/* Return 1 if the integer expressions A - B and -A would overflow, - respectively. Arguments should not have side effects, +/* Return 1 if the integer expression -A would overflow. + Arguments should not have side effects, and can be any signed integer type other than char, bool, a bit-precise integer type, or an enumeration type. These macros are tuned for their last input argument being a constant. */ #if _GL_HAS_BUILTIN_OVERFLOW_P # define _GL_INT_NEGATE_OVERFLOW(a) \ - __builtin_sub_overflow_p (0, a, (__typeof__ (- (a))) 0) + __builtin_sub_overflow_p (0, a, _GL_INT_CONVERT (- (a), 0)) #else # define _GL_INT_NEGATE_OVERFLOW(a) \ _GL_INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) diff --git a/lib/intprops.h b/lib/intprops.h index 924b6f9a46..ed6df2dbc3 100644 --- a/lib/intprops.h +++ b/lib/intprops.h @@ -25,9 +25,20 @@ /* True if the arithmetic type T is an integer type. bool counts as an integer. */ -#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) +#if __STDC_VERSION__ < 201112 || _GL__GENERIC_BOGUS +# define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) +#else +/* Pacify -Wuseless-cast and do not default to the simpler expression; + see <https://gcc.gnu.org/PR125261>. */ +# define TYPE_IS_INTEGER(t) \ + (_Generic ((t) {0}, \ + bool: 1, char: 1, signed char: 1, unsigned char: 1, \ + short int: 1, unsigned short int: 1, int: 1, unsigned int: 1, \ + long int: 1, unsigned long int: 1, long long int: 1, unsigned long long int: 1, \ + float: 0, double: 0, long double: 0)) +#endif -/* True if the real type T is signed. */ +/* True if the standard integer or standard real type T is signed. */ #define TYPE_SIGNED(t) _GL_TYPE_SIGNED (t) /* Return 1 if the real expression E, after promotion, has a @@ -50,12 +61,33 @@ Padding bits are not supported; this is checked at compile-time below. */ #define TYPE_WIDTH(t) _GL_TYPE_WIDTH (t) -/* The maximum and minimum values for the integer type T. */ -#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) -#define TYPE_MAXIMUM(t) \ - ((t) (! TYPE_SIGNED (t) \ - ? (t) -1 \ - : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) +/* The maximum and minimum values for the standard integer type T. */ +#if __STDC_VERSION__ < 201112 || _GL__GENERIC_BOGUS +# define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) +# define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) +#else +/* Pacify -Wuseless-cast and do not default to the simpler expressions; + see <https://gcc.gnu.org/PR125261>. */ +# define TYPE_MINIMUM(t) \ + (_Generic ((t) {0}, \ + bool: (bool) 0, char: (char) CHAR_MIN, \ + signed char: (signed char) SCHAR_MIN, unsigned char: (unsigned char) 0, \ + short int: (short int) SHRT_MIN, unsigned short int: (unsigned short int) 0, \ + int: INT_MIN, unsigned int: 0u, \ + long int: LONG_MIN, unsigned long int: 0ul, \ + long long int: LLONG_MIN, unsigned long long int: 0ull)) +# define TYPE_MAXIMUM(t) \ + (_Generic ((t) {0}, \ + bool: (bool) 1, char: (char) CHAR_MAX, \ + signed char: (signed char) SCHAR_MAX, unsigned char: (unsigned char) -1, \ + short int: (short int) SHRT_MAX, unsigned short int: (unsigned short int) -1, \ + int: INT_MAX, unsigned int: -1u, \ + long int: LONG_MAX, unsigned long int: -1ul, \ + long long int: LLONG_MAX, unsigned long long int: -1ull)) +#endif /* Bound on length of the string representing an unsigned integer value representable in B bits. log10 (2.0) < 146/485. The @@ -184,11 +216,11 @@ that the result (e.g., A + B) has that type. */ #if _GL_HAS_BUILTIN_OVERFLOW_P # define _GL_ADD_OVERFLOW(a, b, min, max) \ - __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0) + __builtin_add_overflow_p (a, b, _GL_INT_CONVERT ((a) + (b), 0)) # define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ - __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0) + __builtin_sub_overflow_p (a, b, _GL_INT_CONVERT ((a) - (b), 0)) # define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ - __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0) + __builtin_mul_overflow_p (a, b, _GL_INT_CONVERT ((a) * (b), 0)) #else # define _GL_ADD_OVERFLOW(a, b, min, max) \ ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \ -- 2.54.0
