summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-10-11 21:00:25 +0200
committerGitHub <noreply@github.com>2021-10-11 21:00:25 +0200
commit2f92e2a590f0e5d2d3093549f5af9a4a1889eb5a (patch)
tree0eee8237edd81885e5e6c9e70686a0c84a44c2db
parent659812b451aefe1f0e5f83540296519a5fb8f313 (diff)
downloadcpython-git-2f92e2a590f0e5d2d3093549f5af9a4a1889eb5a.tar.gz
bpo-45412: Remove Py_SET_ERRNO_ON_MATH_ERROR() macro (GH-28820)
Remove the following math macros using the errno variable: * Py_ADJUST_ERANGE1() * Py_ADJUST_ERANGE2() * Py_OVERFLOWED() * Py_SET_ERANGE_IF_OVERFLOW() * Py_SET_ERRNO_ON_MATH_ERROR() Create pycore_pymath.h internal header file. Rename Py_ADJUST_ERANGE1() and Py_ADJUST_ERANGE2() to _Py_ADJUST_ERANGE1() and _Py_ADJUST_ERANGE2(), and convert these macros to static inline functions. Move the following macros to pycore_pymath.h: * _Py_IntegralTypeSigned() * _Py_IntegralTypeMax() * _Py_IntegralTypeMin() * _Py_InIntegralTypeRange()
-rw-r--r--Doc/whatsnew/3.11.rst10
-rw-r--r--Include/internal/pycore_pymath.h73
-rw-r--r--Include/pymath.h46
-rw-r--r--Include/pyport.h63
-rw-r--r--Misc/NEWS.d/next/C API/2021-10-08-15-54-07.bpo-45412.KHyJCT.rst9
-rw-r--r--Objects/complexobject.c3
-rw-r--r--Objects/floatobject.c3
-rw-r--r--Python/pytime.c5
8 files changed, 99 insertions, 113 deletions
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index e3650a6da8..2262d42a99 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -577,3 +577,13 @@ Removed
Use the new :c:type:`PyConfig` API of the :ref:`Python Initialization Configuration
<init-config>` instead (:pep:`587`).
(Contributed by Victor Stinner in :issue:`44113`.)
+
+* Remove the following math macros using the ``errno`` variable:
+
+ * ``Py_ADJUST_ERANGE1()``
+ * ``Py_ADJUST_ERANGE2()``
+ * ``Py_OVERFLOWED()``
+ * ``Py_SET_ERANGE_IF_OVERFLOW()``
+ * ``Py_SET_ERRNO_ON_MATH_ERROR()``
+
+ (Contributed by Victor Stinner in :issue:`45412`.)
diff --git a/Include/internal/pycore_pymath.h b/Include/internal/pycore_pymath.h
new file mode 100644
index 0000000000..c299c64280
--- /dev/null
+++ b/Include/internal/pycore_pymath.h
@@ -0,0 +1,73 @@
+#ifndef Py_INTERNAL_PYMATH_H
+#define Py_INTERNAL_PYMATH_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+/* _Py_ADJUST_ERANGE1(x)
+ * _Py_ADJUST_ERANGE2(x, y)
+ * Set errno to 0 before calling a libm function, and invoke one of these
+ * macros after, passing the function result(s) (_Py_ADJUST_ERANGE2 is useful
+ * for functions returning complex results). This makes two kinds of
+ * adjustments to errno: (A) If it looks like the platform libm set
+ * errno=ERANGE due to underflow, clear errno. (B) If it looks like the
+ * platform libm overflowed but didn't set errno, force errno to ERANGE. In
+ * effect, we're trying to force a useful implementation of C89 errno
+ * behavior.
+ * Caution:
+ * This isn't reliable. See Py_OVERFLOWED comments.
+ * X and Y may be evaluated more than once.
+ */
+static inline void _Py_ADJUST_ERANGE1(double x)
+{
+ if (errno == 0) {
+ if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL) {
+ errno = ERANGE;
+ }
+ }
+ else if (errno == ERANGE && x == 0.0) {
+ errno = 0;
+ }
+}
+
+static inline void _Py_ADJUST_ERANGE2(double x, double y)
+{
+ if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL ||
+ y == Py_HUGE_VAL || y == -Py_HUGE_VAL)
+ {
+ if (errno == 0) {
+ errno = ERANGE;
+ }
+ }
+ else if (errno == ERANGE) {
+ errno = 0;
+ }
+}
+
+// Return whether integral type *type* is signed or not.
+#define _Py_IntegralTypeSigned(type) \
+ ((type)(-1) < 0)
+
+// Return the maximum value of integral type *type*.
+#define _Py_IntegralTypeMax(type) \
+ ((_Py_IntegralTypeSigned(type)) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0)
+
+// Return the minimum value of integral type *type*.
+#define _Py_IntegralTypeMin(type) \
+ ((_Py_IntegralTypeSigned(type)) ? -_Py_IntegralTypeMax(type) - 1 : 0)
+
+// Check whether *v* is in the range of integral type *type*. This is most
+// useful if *v* is floating-point, since demoting a floating-point *v* to an
+// integral type that cannot represent *v*'s integral part is undefined
+// behavior.
+#define _Py_InIntegralTypeRange(type, v) \
+ (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_PYMATH_H */
diff --git a/Include/pymath.h b/Include/pymath.h
index ebb3b05f1b..39a0bdad98 100644
--- a/Include/pymath.h
+++ b/Include/pymath.h
@@ -176,50 +176,4 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short);
#endif /* __INTEL_COMPILER */
#endif
-/* Py_OVERFLOWED(X)
- * Return 1 iff a libm function overflowed. Set errno to 0 before calling
- * a libm function, and invoke this macro after, passing the function
- * result.
- * Caution:
- * This isn't reliable. C99 no longer requires libm to set errno under
- * any exceptional condition, but does require +- HUGE_VAL return
- * values on overflow. A 754 box *probably* maps HUGE_VAL to a
- * double infinity, and we're cool if that's so, unless the input
- * was an infinity and an infinity is the expected result. A C89
- * system sets errno to ERANGE, so we check for that too. We're
- * out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or
- * if the returned result is a NaN, or if a C89 box returns HUGE_VAL
- * in non-overflow cases.
- * X is evaluated more than once.
- * Some platforms have better way to spell this, so expect some #ifdef'ery.
- *
- * OpenBSD uses 'isinf()' because a compiler bug on that platform causes
- * the longer macro version to be mis-compiled. This isn't optimal, and
- * should be removed once a newer compiler is available on that platform.
- * The system that had the failure was running OpenBSD 3.2 on Intel, with
- * gcc 2.95.3.
- *
- * According to Tim's checkin, the FreeBSD systems use isinf() to work
- * around a FPE bug on that platform.
- */
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
-#define Py_OVERFLOWED(X) isinf(X)
-#else
-#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \
- (X) == Py_HUGE_VAL || \
- (X) == -Py_HUGE_VAL))
-#endif
-
-/* Return whether integral type *type* is signed or not. */
-#define _Py_IntegralTypeSigned(type) ((type)(-1) < 0)
-/* Return the maximum value of integral type *type*. */
-#define _Py_IntegralTypeMax(type) ((_Py_IntegralTypeSigned(type)) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0)
-/* Return the minimum value of integral type *type*. */
-#define _Py_IntegralTypeMin(type) ((_Py_IntegralTypeSigned(type)) ? -_Py_IntegralTypeMax(type) - 1 : 0)
-/* Check whether *v* is in the range of integral type *type*. This is most
- * useful if *v* is floating-point, since demoting a floating-point *v* to an
- * integral type that cannot represent *v*'s integral part is undefined
- * behavior. */
-#define _Py_InIntegralTypeRange(type, v) (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
-
#endif /* Py_PYMATH_H */
diff --git a/Include/pyport.h b/Include/pyport.h
index d27d0838f1..ffc9ba5561 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -316,69 +316,6 @@ extern "C" {
#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE)
#endif
-/* Py_SET_ERRNO_ON_MATH_ERROR(x)
- * If a libm function did not set errno, but it looks like the result
- * overflowed or not-a-number, set errno to ERANGE or EDOM. Set errno
- * to 0 before calling a libm function, and invoke this macro after,
- * passing the function result.
- * Caution:
- * This isn't reliable. See Py_OVERFLOWED comments.
- * X is evaluated more than once.
- */
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__hpux) && defined(__ia64))
-#define _Py_SET_EDOM_FOR_NAN(X) if (isnan(X)) errno = EDOM;
-#else
-#define _Py_SET_EDOM_FOR_NAN(X) ;
-#endif
-#define Py_SET_ERRNO_ON_MATH_ERROR(X) \
- do { \
- if (errno == 0) { \
- if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \
- errno = ERANGE; \
- else _Py_SET_EDOM_FOR_NAN(X) \
- } \
- } while(0)
-
-/* Py_SET_ERANGE_IF_OVERFLOW(x)
- * An alias of Py_SET_ERRNO_ON_MATH_ERROR for backward-compatibility.
- */
-#define Py_SET_ERANGE_IF_OVERFLOW(X) Py_SET_ERRNO_ON_MATH_ERROR(X)
-
-/* Py_ADJUST_ERANGE1(x)
- * Py_ADJUST_ERANGE2(x, y)
- * Set errno to 0 before calling a libm function, and invoke one of these
- * macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful
- * for functions returning complex results). This makes two kinds of
- * adjustments to errno: (A) If it looks like the platform libm set
- * errno=ERANGE due to underflow, clear errno. (B) If it looks like the
- * platform libm overflowed but didn't set errno, force errno to ERANGE. In
- * effect, we're trying to force a useful implementation of C89 errno
- * behavior.
- * Caution:
- * This isn't reliable. See Py_OVERFLOWED comments.
- * X and Y may be evaluated more than once.
- */
-#define Py_ADJUST_ERANGE1(X) \
- do { \
- if (errno == 0) { \
- if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \
- errno = ERANGE; \
- } \
- else if (errno == ERANGE && (X) == 0.0) \
- errno = 0; \
- } while(0)
-
-#define Py_ADJUST_ERANGE2(X, Y) \
- do { \
- if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \
- (Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \
- if (errno == 0) \
- errno = ERANGE; \
- } \
- else if (errno == ERANGE) \
- errno = 0; \
- } while(0)
-
/* The functions _Py_dg_strtod and _Py_dg_dtoa in Python/dtoa.c (which are
* required to support the short float repr introduced in Python 3.1) require
* that the floating-point unit that's being used for arithmetic operations
diff --git a/Misc/NEWS.d/next/C API/2021-10-08-15-54-07.bpo-45412.KHyJCT.rst b/Misc/NEWS.d/next/C API/2021-10-08-15-54-07.bpo-45412.KHyJCT.rst
new file mode 100644
index 0000000000..49746810ee
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2021-10-08-15-54-07.bpo-45412.KHyJCT.rst
@@ -0,0 +1,9 @@
+Remove the following math macros using the ``errno`` variable:
+
+* ``Py_ADJUST_ERANGE1()``
+* ``Py_ADJUST_ERANGE2()``
+* ``Py_OVERFLOWED()``
+* ``Py_SET_ERANGE_IF_OVERFLOW()``
+* ``Py_SET_ERRNO_ON_MATH_ERROR()``
+
+Patch by Victor Stinner.
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index cfe6c73757..f08f03fcb4 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -8,6 +8,7 @@
#include "Python.h"
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_object.h" // _PyObject_Init()
+#include "pycore_pymath.h" // _Py_ADJUST_ERANGE2()
#include "structmember.h" // PyMemberDef
@@ -525,7 +526,7 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
p = _Py_c_pow(a, b);
}
- Py_ADJUST_ERANGE2(p.real, p.imag);
+ _Py_ADJUST_ERANGE2(p.real, p.imag);
if (errno == EDOM) {
PyErr_SetString(PyExc_ZeroDivisionError,
"0.0 to a negative or complex power");
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index e4ce7e74d2..d25d97f4cb 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -8,6 +8,7 @@
#include "pycore_interp.h" // _PyInterpreterState.float_state
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_object.h" // _PyObject_Init()
+#include "pycore_pymath.h" // _Py_ADJUST_ERANGE1()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include <ctype.h>
@@ -809,7 +810,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
*/
errno = 0;
ix = pow(iv, iw);
- Py_ADJUST_ERANGE1(ix);
+ _Py_ADJUST_ERANGE1(ix);
if (negate_result)
ix = -ix;
diff --git a/Python/pytime.c b/Python/pytime.c
index 8865638e91..9653662b0f 100644
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -1,10 +1,11 @@
#include "Python.h"
+#include "pycore_pymath.h" // _Py_InIntegralTypeRange()
#ifdef MS_WINDOWS
-#include <winsock2.h> /* struct timeval */
+# include <winsock2.h> // struct timeval
#endif
#if defined(__APPLE__)
-#include <mach/mach_time.h> /* mach_absolute_time(), mach_timebase_info() */
+# include <mach/mach_time.h> // mach_absolute_time(), mach_timebase_info()
#if defined(__APPLE__) && defined(__has_builtin)
# if __has_builtin(__builtin_available)