Skip to content

Commit 2f92e2a

Browse files
authored
bpo-45412: Remove Py_SET_ERRNO_ON_MATH_ERROR() macro (pythonGH-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()
1 parent 659812b commit 2f92e2a

File tree

8 files changed

+99
-113
lines changed

8 files changed

+99
-113
lines changed

Doc/whatsnew/3.11.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,3 +577,13 @@ Removed
577577
Use the new :c:type:`PyConfig` API of the :ref:`Python Initialization Configuration
578578
<init-config>` instead (:pep:`587`).
579579
(Contributed by Victor Stinner in :issue:`44113`.)
580+
581+
* Remove the following math macros using the ``errno`` variable:
582+
583+
* ``Py_ADJUST_ERANGE1()``
584+
* ``Py_ADJUST_ERANGE2()``
585+
* ``Py_OVERFLOWED()``
586+
* ``Py_SET_ERANGE_IF_OVERFLOW()``
587+
* ``Py_SET_ERRNO_ON_MATH_ERROR()``
588+
589+
(Contributed by Victor Stinner in :issue:`45412`.)

Include/internal/pycore_pymath.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#ifndef Py_INTERNAL_PYMATH_H
2+
#define Py_INTERNAL_PYMATH_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
/* _Py_ADJUST_ERANGE1(x)
12+
* _Py_ADJUST_ERANGE2(x, y)
13+
* Set errno to 0 before calling a libm function, and invoke one of these
14+
* macros after, passing the function result(s) (_Py_ADJUST_ERANGE2 is useful
15+
* for functions returning complex results). This makes two kinds of
16+
* adjustments to errno: (A) If it looks like the platform libm set
17+
* errno=ERANGE due to underflow, clear errno. (B) If it looks like the
18+
* platform libm overflowed but didn't set errno, force errno to ERANGE. In
19+
* effect, we're trying to force a useful implementation of C89 errno
20+
* behavior.
21+
* Caution:
22+
* This isn't reliable. See Py_OVERFLOWED comments.
23+
* X and Y may be evaluated more than once.
24+
*/
25+
static inline void _Py_ADJUST_ERANGE1(double x)
26+
{
27+
if (errno == 0) {
28+
if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL) {
29+
errno = ERANGE;
30+
}
31+
}
32+
else if (errno == ERANGE && x == 0.0) {
33+
errno = 0;
34+
}
35+
}
36+
37+
static inline void _Py_ADJUST_ERANGE2(double x, double y)
38+
{
39+
if (x == Py_HUGE_VAL || x == -Py_HUGE_VAL ||
40+
y == Py_HUGE_VAL || y == -Py_HUGE_VAL)
41+
{
42+
if (errno == 0) {
43+
errno = ERANGE;
44+
}
45+
}
46+
else if (errno == ERANGE) {
47+
errno = 0;
48+
}
49+
}
50+
51+
// Return whether integral type *type* is signed or not.
52+
#define _Py_IntegralTypeSigned(type) \
53+
((type)(-1) < 0)
54+
55+
// Return the maximum value of integral type *type*.
56+
#define _Py_IntegralTypeMax(type) \
57+
((_Py_IntegralTypeSigned(type)) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0)
58+
59+
// Return the minimum value of integral type *type*.
60+
#define _Py_IntegralTypeMin(type) \
61+
((_Py_IntegralTypeSigned(type)) ? -_Py_IntegralTypeMax(type) - 1 : 0)
62+
63+
// Check whether *v* is in the range of integral type *type*. This is most
64+
// useful if *v* is floating-point, since demoting a floating-point *v* to an
65+
// integral type that cannot represent *v*'s integral part is undefined
66+
// behavior.
67+
#define _Py_InIntegralTypeRange(type, v) \
68+
(_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
69+
70+
#ifdef __cplusplus
71+
}
72+
#endif
73+
#endif /* !Py_INTERNAL_PYMATH_H */

Include/pymath.h

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -176,50 +176,4 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short);
176176
#endif /* __INTEL_COMPILER */
177177
#endif
178178

179-
/* Py_OVERFLOWED(X)
180-
* Return 1 iff a libm function overflowed. Set errno to 0 before calling
181-
* a libm function, and invoke this macro after, passing the function
182-
* result.
183-
* Caution:
184-
* This isn't reliable. C99 no longer requires libm to set errno under
185-
* any exceptional condition, but does require +- HUGE_VAL return
186-
* values on overflow. A 754 box *probably* maps HUGE_VAL to a
187-
* double infinity, and we're cool if that's so, unless the input
188-
* was an infinity and an infinity is the expected result. A C89
189-
* system sets errno to ERANGE, so we check for that too. We're
190-
* out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or
191-
* if the returned result is a NaN, or if a C89 box returns HUGE_VAL
192-
* in non-overflow cases.
193-
* X is evaluated more than once.
194-
* Some platforms have better way to spell this, so expect some #ifdef'ery.
195-
*
196-
* OpenBSD uses 'isinf()' because a compiler bug on that platform causes
197-
* the longer macro version to be mis-compiled. This isn't optimal, and
198-
* should be removed once a newer compiler is available on that platform.
199-
* The system that had the failure was running OpenBSD 3.2 on Intel, with
200-
* gcc 2.95.3.
201-
*
202-
* According to Tim's checkin, the FreeBSD systems use isinf() to work
203-
* around a FPE bug on that platform.
204-
*/
205-
#if defined(__FreeBSD__) || defined(__OpenBSD__)
206-
#define Py_OVERFLOWED(X) isinf(X)
207-
#else
208-
#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \
209-
(X) == Py_HUGE_VAL || \
210-
(X) == -Py_HUGE_VAL))
211-
#endif
212-
213-
/* Return whether integral type *type* is signed or not. */
214-
#define _Py_IntegralTypeSigned(type) ((type)(-1) < 0)
215-
/* Return the maximum value of integral type *type*. */
216-
#define _Py_IntegralTypeMax(type) ((_Py_IntegralTypeSigned(type)) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0)
217-
/* Return the minimum value of integral type *type*. */
218-
#define _Py_IntegralTypeMin(type) ((_Py_IntegralTypeSigned(type)) ? -_Py_IntegralTypeMax(type) - 1 : 0)
219-
/* Check whether *v* is in the range of integral type *type*. This is most
220-
* useful if *v* is floating-point, since demoting a floating-point *v* to an
221-
* integral type that cannot represent *v*'s integral part is undefined
222-
* behavior. */
223-
#define _Py_InIntegralTypeRange(type, v) (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
224-
225179
#endif /* Py_PYMATH_H */

Include/pyport.h

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -316,69 +316,6 @@ extern "C" {
316316
#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE)
317317
#endif
318318

319-
/* Py_SET_ERRNO_ON_MATH_ERROR(x)
320-
* If a libm function did not set errno, but it looks like the result
321-
* overflowed or not-a-number, set errno to ERANGE or EDOM. Set errno
322-
* to 0 before calling a libm function, and invoke this macro after,
323-
* passing the function result.
324-
* Caution:
325-
* This isn't reliable. See Py_OVERFLOWED comments.
326-
* X is evaluated more than once.
327-
*/
328-
#if defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__hpux) && defined(__ia64))
329-
#define _Py_SET_EDOM_FOR_NAN(X) if (isnan(X)) errno = EDOM;
330-
#else
331-
#define _Py_SET_EDOM_FOR_NAN(X) ;
332-
#endif
333-
#define Py_SET_ERRNO_ON_MATH_ERROR(X) \
334-
do { \
335-
if (errno == 0) { \
336-
if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \
337-
errno = ERANGE; \
338-
else _Py_SET_EDOM_FOR_NAN(X) \
339-
} \
340-
} while(0)
341-
342-
/* Py_SET_ERANGE_IF_OVERFLOW(x)
343-
* An alias of Py_SET_ERRNO_ON_MATH_ERROR for backward-compatibility.
344-
*/
345-
#define Py_SET_ERANGE_IF_OVERFLOW(X) Py_SET_ERRNO_ON_MATH_ERROR(X)
346-
347-
/* Py_ADJUST_ERANGE1(x)
348-
* Py_ADJUST_ERANGE2(x, y)
349-
* Set errno to 0 before calling a libm function, and invoke one of these
350-
* macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful
351-
* for functions returning complex results). This makes two kinds of
352-
* adjustments to errno: (A) If it looks like the platform libm set
353-
* errno=ERANGE due to underflow, clear errno. (B) If it looks like the
354-
* platform libm overflowed but didn't set errno, force errno to ERANGE. In
355-
* effect, we're trying to force a useful implementation of C89 errno
356-
* behavior.
357-
* Caution:
358-
* This isn't reliable. See Py_OVERFLOWED comments.
359-
* X and Y may be evaluated more than once.
360-
*/
361-
#define Py_ADJUST_ERANGE1(X) \
362-
do { \
363-
if (errno == 0) { \
364-
if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \
365-
errno = ERANGE; \
366-
} \
367-
else if (errno == ERANGE && (X) == 0.0) \
368-
errno = 0; \
369-
} while(0)
370-
371-
#define Py_ADJUST_ERANGE2(X, Y) \
372-
do { \
373-
if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \
374-
(Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \
375-
if (errno == 0) \
376-
errno = ERANGE; \
377-
} \
378-
else if (errno == ERANGE) \
379-
errno = 0; \
380-
} while(0)
381-
382319
/* The functions _Py_dg_strtod and _Py_dg_dtoa in Python/dtoa.c (which are
383320
* required to support the short float repr introduced in Python 3.1) require
384321
* that the floating-point unit that's being used for arithmetic operations
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Remove the following math macros using the ``errno`` variable:
2+
3+
* ``Py_ADJUST_ERANGE1()``
4+
* ``Py_ADJUST_ERANGE2()``
5+
* ``Py_OVERFLOWED()``
6+
* ``Py_SET_ERANGE_IF_OVERFLOW()``
7+
* ``Py_SET_ERRNO_ON_MATH_ERROR()``
8+
9+
Patch by Victor Stinner.

Objects/complexobject.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "Python.h"
99
#include "pycore_long.h" // _PyLong_GetZero()
1010
#include "pycore_object.h" // _PyObject_Init()
11+
#include "pycore_pymath.h" // _Py_ADJUST_ERANGE2()
1112
#include "structmember.h" // PyMemberDef
1213

1314

@@ -525,7 +526,7 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
525526
p = _Py_c_pow(a, b);
526527
}
527528

528-
Py_ADJUST_ERANGE2(p.real, p.imag);
529+
_Py_ADJUST_ERANGE2(p.real, p.imag);
529530
if (errno == EDOM) {
530531
PyErr_SetString(PyExc_ZeroDivisionError,
531532
"0.0 to a negative or complex power");

Objects/floatobject.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "pycore_interp.h" // _PyInterpreterState.float_state
99
#include "pycore_long.h" // _PyLong_GetOne()
1010
#include "pycore_object.h" // _PyObject_Init()
11+
#include "pycore_pymath.h" // _Py_ADJUST_ERANGE1()
1112
#include "pycore_pystate.h" // _PyInterpreterState_GET()
1213

1314
#include <ctype.h>
@@ -809,7 +810,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
809810
*/
810811
errno = 0;
811812
ix = pow(iv, iw);
812-
Py_ADJUST_ERANGE1(ix);
813+
_Py_ADJUST_ERANGE1(ix);
813814
if (negate_result)
814815
ix = -ix;
815816

Python/pytime.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#include "Python.h"
2+
#include "pycore_pymath.h" // _Py_InIntegralTypeRange()
23
#ifdef MS_WINDOWS
3-
#include <winsock2.h> /* struct timeval */
4+
# include <winsock2.h> // struct timeval
45
#endif
56

67
#if defined(__APPLE__)
7-
#include <mach/mach_time.h> /* mach_absolute_time(), mach_timebase_info() */
8+
# include <mach/mach_time.h> // mach_absolute_time(), mach_timebase_info()
89

910
#if defined(__APPLE__) && defined(__has_builtin)
1011
# if __has_builtin(__builtin_available)

0 commit comments

Comments
 (0)