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


Reply via email to