gh-61103: don't use C _Complex types to implement F/D/G in ctypes (GH-133237)
According to the C standard, the memory representation of _Complex types is equivalent to 2-element arrays. Unlike _Complex, arrays are always available. - drop _complex.h header - use appropriate real arrays to replace complex types Co-authored-by: Lisandro Dalcin <dalcinl@gmail.com> Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
This commit is contained in:
parent
d530e74e44
commit
8d0e07eb89
@ -3313,7 +3313,7 @@ MODULE_CMATH_DEPS=$(srcdir)/Modules/_math.h
|
|||||||
MODULE_MATH_DEPS=$(srcdir)/Modules/_math.h
|
MODULE_MATH_DEPS=$(srcdir)/Modules/_math.h
|
||||||
MODULE_PYEXPAT_DEPS=@LIBEXPAT_INTERNAL@
|
MODULE_PYEXPAT_DEPS=@LIBEXPAT_INTERNAL@
|
||||||
MODULE_UNICODEDATA_DEPS=$(srcdir)/Modules/unicodedata_db.h $(srcdir)/Modules/unicodename_db.h
|
MODULE_UNICODEDATA_DEPS=$(srcdir)/Modules/unicodedata_db.h $(srcdir)/Modules/unicodename_db.h
|
||||||
MODULE__CTYPES_DEPS=$(srcdir)/Modules/_ctypes/ctypes.h $(srcdir)/Modules/_complex.h
|
MODULE__CTYPES_DEPS=$(srcdir)/Modules/_ctypes/ctypes.h
|
||||||
MODULE__CTYPES_TEST_DEPS=$(srcdir)/Modules/_ctypes/_ctypes_test_generated.c.h
|
MODULE__CTYPES_TEST_DEPS=$(srcdir)/Modules/_ctypes/_ctypes_test_generated.c.h
|
||||||
MODULE__CTYPES_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@
|
MODULE__CTYPES_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@
|
||||||
MODULE__DECIMAL_DEPS=$(srcdir)/Modules/_decimal/docstrings.h @LIBMPDEC_INTERNAL@
|
MODULE__DECIMAL_DEPS=$(srcdir)/Modules/_decimal/docstrings.h @LIBMPDEC_INTERNAL@
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
/* Workarounds for buggy complex number arithmetic implementations. */
|
|
||||||
|
|
||||||
#ifndef Py_HAVE_C_COMPLEX
|
|
||||||
# error "this header file should only be included if Py_HAVE_C_COMPLEX is defined"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <complex.h>
|
|
||||||
|
|
||||||
/* Other compilers (than clang), that claims to
|
|
||||||
implement C11 *and* define __STDC_IEC_559_COMPLEX__ - don't have
|
|
||||||
issue with CMPLX(). This is specific to glibc & clang combination:
|
|
||||||
https://sourceware.org/bugzilla/show_bug.cgi?id=26287
|
|
||||||
|
|
||||||
Here we fallback to using __builtin_complex(), available in clang
|
|
||||||
v12+. Else CMPLX implemented following C11 6.2.5p13: "Each complex type
|
|
||||||
has the same representation and alignment requirements as an array
|
|
||||||
type containing exactly two elements of the corresponding real type;
|
|
||||||
the first element is equal to the real part, and the second element
|
|
||||||
to the imaginary part, of the complex number.
|
|
||||||
*/
|
|
||||||
#if !defined(CMPLX)
|
|
||||||
# if defined(__clang__) && __has_builtin(__builtin_complex)
|
|
||||||
# define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
|
|
||||||
# define CMPLXF(x, y) __builtin_complex ((float) (x), (float) (y))
|
|
||||||
# define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
|
|
||||||
# else
|
|
||||||
static inline double complex
|
|
||||||
CMPLX(double real, double imag)
|
|
||||||
{
|
|
||||||
double complex z;
|
|
||||||
((double *)(&z))[0] = real;
|
|
||||||
((double *)(&z))[1] = imag;
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float complex
|
|
||||||
CMPLXF(float real, float imag)
|
|
||||||
{
|
|
||||||
float complex z;
|
|
||||||
((float *)(&z))[0] = real;
|
|
||||||
((float *)(&z))[1] = imag;
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline long double complex
|
|
||||||
CMPLXL(long double real, long double imag)
|
|
||||||
{
|
|
||||||
long double complex z;
|
|
||||||
((long double *)(&z))[0] = real;
|
|
||||||
((long double *)(&z))[1] = imag;
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
#endif
|
|
@ -24,7 +24,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
||||||
# include "../_complex.h" // csqrt()
|
# include <complex.h> // csqrt()
|
||||||
# undef I // for _ctypes_test_generated.c.h
|
# undef I // for _ctypes_test_generated.c.h
|
||||||
#endif
|
#endif
|
||||||
#include <stdio.h> // printf()
|
#include <stdio.h> // printf()
|
||||||
|
@ -103,9 +103,6 @@ module _ctypes
|
|||||||
#include "pycore_global_objects.h"// _Py_ID()
|
#include "pycore_global_objects.h"// _Py_ID()
|
||||||
#include "pycore_traceback.h" // _PyTraceback_Add()
|
#include "pycore_traceback.h" // _PyTraceback_Add()
|
||||||
|
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
|
||||||
#include "../_complex.h" // complex
|
|
||||||
#endif
|
|
||||||
#define clinic_state() (get_module_state(module))
|
#define clinic_state() (get_module_state(module))
|
||||||
#include "clinic/callproc.c.h"
|
#include "clinic/callproc.c.h"
|
||||||
#undef clinic_state
|
#undef clinic_state
|
||||||
@ -652,11 +649,9 @@ union result {
|
|||||||
double d;
|
double d;
|
||||||
float f;
|
float f;
|
||||||
void *p;
|
void *p;
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
double D[2];
|
||||||
double complex D;
|
float F[2];
|
||||||
float complex F;
|
long double G[2];
|
||||||
long double complex G;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct argument {
|
struct argument {
|
||||||
|
@ -14,10 +14,6 @@
|
|||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
#include "ctypes.h"
|
#include "ctypes.h"
|
||||||
|
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
|
||||||
# include "../_complex.h" // complex
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
|
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
@ -763,18 +759,25 @@ d_get(void *ptr, Py_ssize_t size)
|
|||||||
return PyFloat_FromDouble(val);
|
return PyFloat_FromDouble(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
#if defined(Py_FFI_SUPPORT_C_COMPLEX)
|
||||||
|
|
||||||
|
/* We don't use _Complex types here, using arrays instead, as the C11+
|
||||||
|
standard says: "Each complex type has the same representation and alignment
|
||||||
|
requirements as an array type containing exactly two elements of the
|
||||||
|
corresponding real type; the first element is equal to the real part, and
|
||||||
|
the second element to the imaginary part, of the complex number." */
|
||||||
|
|
||||||
/* D: double complex */
|
/* D: double complex */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
D_set(void *ptr, PyObject *value, Py_ssize_t size)
|
D_set(void *ptr, PyObject *value, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
assert(NUM_BITS(size) || (size == sizeof(double complex)));
|
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
|
||||||
Py_complex c = PyComplex_AsCComplex(value);
|
Py_complex c = PyComplex_AsCComplex(value);
|
||||||
|
|
||||||
if (c.real == -1 && PyErr_Occurred()) {
|
if (c.real == -1 && PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
double complex x = CMPLX(c.real, c.imag);
|
double x[2] = {c.real, c.imag};
|
||||||
memcpy(ptr, &x, sizeof(x));
|
memcpy(ptr, &x, sizeof(x));
|
||||||
_RET(value);
|
_RET(value);
|
||||||
}
|
}
|
||||||
@ -782,24 +785,24 @@ D_set(void *ptr, PyObject *value, Py_ssize_t size)
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
D_get(void *ptr, Py_ssize_t size)
|
D_get(void *ptr, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
assert(NUM_BITS(size) || (size == sizeof(double complex)));
|
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
|
||||||
double complex x;
|
double x[2];
|
||||||
|
|
||||||
memcpy(&x, ptr, sizeof(x));
|
memcpy(&x, ptr, sizeof(x));
|
||||||
return PyComplex_FromDoubles(creal(x), cimag(x));
|
return PyComplex_FromDoubles(x[0], x[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* F: float complex */
|
/* F: float complex */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
F_set(void *ptr, PyObject *value, Py_ssize_t size)
|
F_set(void *ptr, PyObject *value, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
assert(NUM_BITS(size) || (size == sizeof(float complex)));
|
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
|
||||||
Py_complex c = PyComplex_AsCComplex(value);
|
Py_complex c = PyComplex_AsCComplex(value);
|
||||||
|
|
||||||
if (c.real == -1 && PyErr_Occurred()) {
|
if (c.real == -1 && PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
float complex x = CMPLXF((float)c.real, (float)c.imag);
|
float x[2] = {(float)c.real, (float)c.imag};
|
||||||
memcpy(ptr, &x, sizeof(x));
|
memcpy(ptr, &x, sizeof(x));
|
||||||
_RET(value);
|
_RET(value);
|
||||||
}
|
}
|
||||||
@ -807,24 +810,24 @@ F_set(void *ptr, PyObject *value, Py_ssize_t size)
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
F_get(void *ptr, Py_ssize_t size)
|
F_get(void *ptr, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
assert(NUM_BITS(size) || (size == sizeof(float complex)));
|
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
|
||||||
float complex x;
|
float x[2];
|
||||||
|
|
||||||
memcpy(&x, ptr, sizeof(x));
|
memcpy(&x, ptr, sizeof(x));
|
||||||
return PyComplex_FromDoubles(crealf(x), cimagf(x));
|
return PyComplex_FromDoubles(x[0], x[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* G: long double complex */
|
/* G: long double complex */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
G_set(void *ptr, PyObject *value, Py_ssize_t size)
|
G_set(void *ptr, PyObject *value, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
assert(NUM_BITS(size) || (size == sizeof(long double complex)));
|
assert(NUM_BITS(size) || (size == 2*sizeof(long double)));
|
||||||
Py_complex c = PyComplex_AsCComplex(value);
|
Py_complex c = PyComplex_AsCComplex(value);
|
||||||
|
|
||||||
if (c.real == -1 && PyErr_Occurred()) {
|
if (c.real == -1 && PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
long double complex x = CMPLXL(c.real, c.imag);
|
long double x[2] = {c.real, c.imag};
|
||||||
memcpy(ptr, &x, sizeof(x));
|
memcpy(ptr, &x, sizeof(x));
|
||||||
_RET(value);
|
_RET(value);
|
||||||
}
|
}
|
||||||
@ -832,11 +835,11 @@ G_set(void *ptr, PyObject *value, Py_ssize_t size)
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
G_get(void *ptr, Py_ssize_t size)
|
G_get(void *ptr, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
assert(NUM_BITS(size) || (size == sizeof(long double complex)));
|
assert(NUM_BITS(size) || (size == 2*sizeof(long double)));
|
||||||
long double complex x;
|
long double x[2];
|
||||||
|
|
||||||
memcpy(&x, ptr, sizeof(x));
|
memcpy(&x, ptr, sizeof(x));
|
||||||
return PyComplex_FromDoubles((double)creall(x), (double)cimagl(x));
|
return PyComplex_FromDoubles((double)x[0], (double)x[1]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1596,7 +1599,7 @@ for base_code, base_c_type in [
|
|||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TABLE_ENTRY_SW(d, &ffi_type_double);
|
TABLE_ENTRY_SW(d, &ffi_type_double);
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
#if defined(Py_FFI_SUPPORT_C_COMPLEX)
|
||||||
if (Py_FFI_COMPLEX_AVAILABLE) {
|
if (Py_FFI_COMPLEX_AVAILABLE) {
|
||||||
TABLE_ENTRY(D, &ffi_type_complex_double);
|
TABLE_ENTRY(D, &ffi_type_complex_double);
|
||||||
TABLE_ENTRY(F, &ffi_type_complex_float);
|
TABLE_ENTRY(F, &ffi_type_complex_float);
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
|
|
||||||
// Do we support C99 complex types in ffi?
|
// Do we support C99 complex types in ffi?
|
||||||
// For Apple's libffi, this must be determined at runtime (see gh-128156).
|
// For Apple's libffi, this must be determined at runtime (see gh-128156).
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
#if defined(Py_FFI_SUPPORT_C_COMPLEX)
|
||||||
# include "../_complex.h" // complex
|
|
||||||
# if USING_APPLE_OS_LIBFFI && defined(__has_builtin)
|
# if USING_APPLE_OS_LIBFFI && defined(__has_builtin)
|
||||||
# if __has_builtin(__builtin_available)
|
# if __has_builtin(__builtin_available)
|
||||||
# define Py_FFI_COMPLEX_AVAILABLE __builtin_available(macOS 10.15, *)
|
# define Py_FFI_COMPLEX_AVAILABLE __builtin_available(macOS 10.15, *)
|
||||||
@ -494,11 +493,9 @@ struct tagPyCArgObject {
|
|||||||
double d;
|
double d;
|
||||||
float f;
|
float f;
|
||||||
void *p;
|
void *p;
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
double D[2];
|
||||||
double complex D;
|
float F[2];
|
||||||
float complex F;
|
long double G[2];
|
||||||
long double complex G;
|
|
||||||
#endif
|
|
||||||
} value;
|
} value;
|
||||||
PyObject *obj;
|
PyObject *obj;
|
||||||
Py_ssize_t size; /* for the 'V' tag */
|
Py_ssize_t size; /* for the 'V' tag */
|
||||||
|
@ -853,8 +853,8 @@ static const formatdef native_table[] = {
|
|||||||
{'e', sizeof(short), _Alignof(short), nu_halffloat, np_halffloat},
|
{'e', sizeof(short), _Alignof(short), nu_halffloat, np_halffloat},
|
||||||
{'f', sizeof(float), _Alignof(float), nu_float, np_float},
|
{'f', sizeof(float), _Alignof(float), nu_float, np_float},
|
||||||
{'d', sizeof(double), _Alignof(double), nu_double, np_double},
|
{'d', sizeof(double), _Alignof(double), nu_double, np_double},
|
||||||
{'F', 2*sizeof(float), _Alignof(float[2]), nu_float_complex, np_float_complex},
|
{'F', 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex},
|
||||||
{'D', 2*sizeof(double), _Alignof(double[2]), nu_double_complex, np_double_complex},
|
{'D', 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex},
|
||||||
{'P', sizeof(void *), _Alignof(void *), nu_void_p, np_void_p},
|
{'P', sizeof(void *), _Alignof(void *), nu_void_p, np_void_p},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user