]> Savannah Git Hosting - gnulib.git/commitdiff
intprops.h, verify.h: port better to clang
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 26 Aug 2019 02:29:15 +0000 (19:29 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 26 Aug 2019 02:30:00 +0000 (19:30 -0700)
Improve code generated by INT_ADD_WRAPV and INT_SUBTRACT_WRAPV
with Clang.  Problem reported privately by Mattias Engdegård.
Also, insulate intprops.h and verify.h better against each other’s
definitions of __has_builtin on non-Clang hosts.
* lib/intprops.h (__has_builtin): Define a temporary substitute
if __has_builtin is not already defined.
(_GL_HAS___builtin_add_overflow, _GL_TEMPDEF___has_builtin):
New temporary internal macros.
(_GL_HAS_BUILTIN_ADD_OVERFLOW, _GL_HAS_BUILTIN_MUL_OVERFLOW):
Now two separate macros, replacing the old
_GL_HAS_BUILTIN_OVERFLOW, since we no longer assume that
__builtin_mul_overflow is like the rest.  All uses changed.
(INT_ADD_WRAPV, INT_SUBTRACT_WRAPV, INT_MULTIPLY_WRAPV):
Adjust to above changes.
(_GL_INT_OP_WRAPV): Remove ‘builtin’ arg, since it’s no
longer relevant.  All uses changed.
* lib/verify.h (__has_builtin): Treat like intprops.h,
so that the two .h files do not collide with each other.
(_GL_HAS___builtin_unreachable, _GL_HAS___builtin_trap)
(_GL_TEMPDEF___has_builtin): New temporary internal macros.

ChangeLog
lib/intprops.h
lib/verify.h

index f7fbcf41352f6fc6740e8a8e5ceafaad1cd9f8c7..e6f5a096ada11ae5fa15fec4e71839e1087153be 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2019-08-25  Paul Eggert  <eggert@cs.ucla.edu>
+
+       intprops.h, verify.h: port better to clang
+       Improve code generated by INT_ADD_WRAPV and INT_SUBTRACT_WRAPV
+       with Clang.  Problem reported privately by Mattias Engdegård.
+       Also, insulate intprops.h and verify.h better against each other’s
+       definitions of __has_builtin on non-Clang hosts.
+       * lib/intprops.h (__has_builtin): Define a temporary substitute
+       if __has_builtin is not already defined.
+       (_GL_HAS___builtin_add_overflow, _GL_TEMPDEF___has_builtin):
+       New temporary internal macros.
+       (_GL_HAS_BUILTIN_ADD_OVERFLOW, _GL_HAS_BUILTIN_MUL_OVERFLOW):
+       Now two separate macros, replacing the old
+       _GL_HAS_BUILTIN_OVERFLOW, since we no longer assume that
+       __builtin_mul_overflow is like the rest.  All uses changed.
+       (INT_ADD_WRAPV, INT_SUBTRACT_WRAPV, INT_MULTIPLY_WRAPV):
+       Adjust to above changes.
+       (_GL_INT_OP_WRAPV): Remove ‘builtin’ arg, since it’s no
+       longer relevant.  All uses changed.
+       * lib/verify.h (__has_builtin): Treat like intprops.h,
+       so that the two .h files do not collide with each other.
+       (_GL_HAS___builtin_unreachable, _GL_HAS___builtin_trap)
+       (_GL_TEMPDEF___has_builtin): New temporary internal macros.
+
 2019-08-24  Paul Eggert  <eggert@cs.ucla.edu>
 
        intprops: say why not Clang __builtin_add_overflow
index fbbc3cffe004e17c319688a7e18a32c394c7cb3e..ffd737028482246f0ffda34b0b3e5774e50435ba 100644 (file)
 
 #include <limits.h>
 
+/* If the compiler lacks __has_builtin, define it well enough for this
+   source file only.  */
+#ifndef __has_builtin
+# define __has_builtin(x) _GL_HAS_##x
+# if 5 <= __GNUC__ && !defined __ICC
+#  define _GL_HAS___builtin_add_overflow 1
+# else
+#  define _GL_HAS___builtin_add_overflow 0
+# endif
+# define _GL_TEMPDEF___has_builtin
+#endif
+
 /* Return a value with the common real type of E and V and the value of V.
    Do not evaluate E.  */
 #define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
    ? (a) < (min) >> (b)                                 \
    : (max) >> (b) < (a))
 
-/* True if __builtin_add_overflow (A, B, P) works when P is non-null.
-   See <https://bugs.llvm.org/show_bug.cgi?id=16404> for why this is
-   false for Clang.  */
-#if 5 <= __GNUC__ && !defined __ICC
-# define _GL_HAS_BUILTIN_OVERFLOW 1
+/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow
+   (A, B, P) work when P is non-null.  */
+#if __has_builtin (__builtin_add_overflow)
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
+#else
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
+#endif
+
+/* True if __builtin_mul_overflow (A, B, P) works when P is non-null.  */
+#ifdef __clang__
+/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>.  */
+# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
 #else
-# define _GL_HAS_BUILTIN_OVERFLOW 0
+# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW
 #endif
 
-/* True if __builtin_add_overflow_p (A, B, C) works.  */
+/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
+   __builtin_mul_overflow_p and __builtin_mul_overflow_p.  */
 #define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
 
 /* The _GL*_OVERFLOW macros have the same restrictions as the
 
 /* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
    Return 1 if the result overflows.  See above for restrictions.  */
-#define INT_ADD_WRAPV(a, b, r) \
-  _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, \
-                    _GL_INT_ADD_RANGE_OVERFLOW)
-#define INT_SUBTRACT_WRAPV(a, b, r) \
-  _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, \
-                    _GL_INT_SUBTRACT_RANGE_OVERFLOW)
-#define INT_MULTIPLY_WRAPV(a, b, r) \
-   _GL_INT_OP_WRAPV (a, b, r, *, _GL_BUILTIN_MUL_OVERFLOW, \
-                     _GL_INT_MULTIPLY_RANGE_OVERFLOW)
-
-/* Like __builtin_mul_overflow, but work around GCC bug 91450.  */
-#define _GL_BUILTIN_MUL_OVERFLOW(a, b, r) \
-  ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && EXPR_SIGNED (a) && EXPR_SIGNED (b) \
-    && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
-   ? ((void) __builtin_mul_overflow (a, b, r), 1) \
-   : __builtin_mul_overflow (a, b, r))
+#if _GL_HAS_BUILTIN_ADD_OVERFLOW
+# define INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r)
+# define INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r)
+#else
+# define INT_ADD_WRAPV(a, b, r) \
+   _GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW)
+# define INT_SUBTRACT_WRAPV(a, b, r) \
+   _GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
+#endif
+#if _GL_HAS_BUILTIN_MUL_OVERFLOW
+/* Work around GCC bug 91450.  */
+# define INT_MULTIPLY_WRAPV(a, b, r) \
+   ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && EXPR_SIGNED (a) && EXPR_SIGNED (b) \
+     && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
+    ? ((void) __builtin_mul_overflow (a, b, r), 1) \
+    : __builtin_mul_overflow (a, b, r))
+#else
+# define INT_MULTIPLY_WRAPV(a, b, r) \
+   _GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
+#endif
 
 /* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390.  See:
    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
    https://llvm.org/bugs/show_bug.cgi?id=25390
    For now, assume all versions of GCC-like compilers generate bogus
-   warnings for _Generic.  This matters only for older compilers that
-   lack __builtin_add_overflow.  */
+   warnings for _Generic.  This matters only for compilers that
+   lack relevant builtins.  */
 #if __GNUC__
 # define _GL__GENERIC_BOGUS 1
 #else
 #endif
 
 /* Store the low-order bits of A <op> B into *R, where OP specifies
-   the operation.  BUILTIN is the builtin operation, and OVERFLOW the
-   overflow predicate.  Return 1 if the result overflows.  See above
-   for restrictions.  */
-#if _GL_HAS_BUILTIN_OVERFLOW
-# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r)
-#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
-# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
+   the operation and OVERFLOW the overflow predicate.  Return 1 if the
+   result overflows.  See above for restrictions.  */
+#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
+# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
    (_Generic \
     (*(r), \
      signed char: \
         : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0)))
 # endif
 
-# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
+# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
    (sizeof *(r) == sizeof (signed char) \
     ? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
                                  signed char, SCHAR_MIN, SCHAR_MAX, \
          : (tmin) / (a) < (b)) \
       : (tmax) / (b) < (a)))
 
+#ifdef _GL_TEMPDEF___has_builtin
+# undef __has_builtin
+# undef _GL_HAS___builtin_add_overflow
+# undef _GL_TEMPDEF___has_builtin
+#endif
+
 #endif /* _GL_INTPROPS_H */
index afdc1ad81f1a6b0e9de6976e8531b9f26d6f7875..06e975ebf65ee80cbaaf92f3526ee5345d1da3b5 100644 (file)
 # undef _Static_assert
 #endif
 
+/* If the compiler lacks __has_builtin, define it well enough for this
+   source file only.  */
+#ifndef __has_builtin
+# define __has_builtin(x) _GL_HAS_##x
+# define _GL_HAS___builtin_unreachable (4 < __GNUC__ + (5 <= __GNUC_MINOR__))
+# define _GL_HAS___builtin_trap \
+    (3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__)))
+# define _GL_TEMPDEF___has_builtin
+#endif
+
 /* Each of these macros verifies that its argument R is nonzero.  To
    be portable, R should be an integer constant expression.  Unlike
    assert (R), there is no run-time overhead.
@@ -260,24 +270,17 @@ template <int w>
 # define verify(R) _GL_VERIFY (R, "verify (" #R ")", -)
 #endif
 
-#ifndef __has_builtin
-# define __has_builtin(x) 0
-#endif
-
 /* Assume that R always holds.  Behavior is undefined if R is false,
    fails to evaluate, or has side effects.  Although assuming R can
    help a compiler generate better code or diagnostics, performance
    can suffer if R uses hard-to-optimize features such as function
    calls not inlined by the compiler.  */
 
-#if (__has_builtin (__builtin_unreachable) \
-     || 4 < __GNUC__ + (5 <= __GNUC_MINOR__))
+#if __has_builtin (__builtin_unreachable)
 # define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
 #elif 1200 <= _MSC_VER
 # define assume(R) __assume (R)
-#elif ((defined GCC_LINT || defined lint) \
-       && (__has_builtin (__builtin_trap) \
-           || 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))))
+#elif (defined GCC_LINT || defined lint) && __has_builtin (__builtin_trap)
   /* Doing it this way helps various packages when configured with
      --enable-gcc-warnings, which compiles with -Dlint.  It's nicer
      when 'assume' silences warnings even with older GCCs.  */
@@ -287,6 +290,13 @@ template <int w>
 # define assume(R) ((R) ? (void) 0 : /*NOTREACHED*/ (void) 0)
 #endif
 
+#ifdef _GL_TEMPDEF___has_builtin
+# undef __has_builtin
+# undef _GL_HAS___builtin_unreachable
+# undef _GL_HAS___builtin_trap
+# undef _GL_TEMPDEF___has_builtin
+#endif
+
 /* @assert.h omit end@  */
 
 #endif