https://github.com/python/cpython/commit/8d0e07eb8993cb8b084a577e79083e8112ef8c7f
commit: 8d0e07eb8993cb8b084a577e79083e8112ef8c7f
branch: main
author: Sergey B Kirpichev <skirpic...@gmail.com>
committer: encukou <encu...@gmail.com>
date: 2025-05-05T11:23:30+02:00
summary:

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 <dalc...@gmail.com>
Co-authored-by: Petr Viktorin <encu...@gmail.com>
Co-authored-by: Stan Ulbrych <89152624+stanfromirel...@users.noreply.github.com>

files:
D Modules/_complex.h
M Makefile.pre.in
M Modules/_ctypes/_ctypes_test.c
M Modules/_ctypes/callproc.c
M Modules/_ctypes/cfield.c
M Modules/_ctypes/ctypes.h
M Modules/_struct.c

diff --git a/Makefile.pre.in b/Makefile.pre.in
index 190094af19d6c9..3fda59cdcec71b 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -3313,7 +3313,7 @@ MODULE_CMATH_DEPS=$(srcdir)/Modules/_math.h
 MODULE_MATH_DEPS=$(srcdir)/Modules/_math.h
 MODULE_PYEXPAT_DEPS=@LIBEXPAT_INTERNAL@
 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_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@
 MODULE__DECIMAL_DEPS=$(srcdir)/Modules/_decimal/docstrings.h 
@LIBMPDEC_INTERNAL@
diff --git a/Modules/_complex.h b/Modules/_complex.h
deleted file mode 100644
index 28d4a32794b97c..00000000000000
--- a/Modules/_complex.h
+++ /dev/null
@@ -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
diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c
index 2268072545f45d..557bfa85b1ea29 100644
--- a/Modules/_ctypes/_ctypes_test.c
+++ b/Modules/_ctypes/_ctypes_test.c
@@ -24,7 +24,7 @@
 #endif
 
 #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
 #endif
 #include <stdio.h>                // printf()
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index fc7265cb63ed9e..856b0376e5eaa0 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -103,9 +103,6 @@ module _ctypes
 #include "pycore_global_objects.h"// _Py_ID()
 #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))
 #include "clinic/callproc.c.h"
 #undef clinic_state
@@ -652,11 +649,9 @@ union result {
     double d;
     float f;
     void *p;
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
-    double complex D;
-    float complex F;
-    long double complex G;
-#endif
+    double D[2];
+    float F[2];
+    long double G[2];
 };
 
 struct argument {
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 580ea18af2a43a..86bcc805360a3f 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -14,10 +14,6 @@
 #include <ffi.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"
 
 /*[clinic input]
@@ -763,18 +759,25 @@ d_get(void *ptr, Py_ssize_t size)
     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 */
 static PyObject *
 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);
 
     if (c.real == -1 && PyErr_Occurred()) {
         return NULL;
     }
-    double complex x = CMPLX(c.real, c.imag);
+    double x[2] = {c.real, c.imag};
     memcpy(ptr, &x, sizeof(x));
     _RET(value);
 }
@@ -782,24 +785,24 @@ D_set(void *ptr, PyObject *value, Py_ssize_t size)
 static PyObject *
 D_get(void *ptr, Py_ssize_t size)
 {
-    assert(NUM_BITS(size) || (size == sizeof(double complex)));
-    double complex x;
+    assert(NUM_BITS(size) || (size == 2*sizeof(double)));
+    double x[2];
 
     memcpy(&x, ptr, sizeof(x));
-    return PyComplex_FromDoubles(creal(x), cimag(x));
+    return PyComplex_FromDoubles(x[0], x[1]);
 }
 
 /* F: float complex */
 static PyObject *
 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);
 
     if (c.real == -1 && PyErr_Occurred()) {
         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));
     _RET(value);
 }
@@ -807,24 +810,24 @@ F_set(void *ptr, PyObject *value, Py_ssize_t size)
 static PyObject *
 F_get(void *ptr, Py_ssize_t size)
 {
-    assert(NUM_BITS(size) || (size == sizeof(float complex)));
-    float complex x;
+    assert(NUM_BITS(size) || (size == 2*sizeof(float)));
+    float x[2];
 
     memcpy(&x, ptr, sizeof(x));
-    return PyComplex_FromDoubles(crealf(x), cimagf(x));
+    return PyComplex_FromDoubles(x[0], x[1]);
 }
 
 /* G: long double complex */
 static PyObject *
 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);
 
     if (c.real == -1 && PyErr_Occurred()) {
         return NULL;
     }
-    long double complex x = CMPLXL(c.real, c.imag);
+    long double x[2] = {c.real, c.imag};
     memcpy(ptr, &x, sizeof(x));
     _RET(value);
 }
@@ -832,11 +835,11 @@ G_set(void *ptr, PyObject *value, Py_ssize_t size)
 static PyObject *
 G_get(void *ptr, Py_ssize_t size)
 {
-    assert(NUM_BITS(size) || (size == sizeof(long double complex)));
-    long double complex x;
+    assert(NUM_BITS(size) || (size == 2*sizeof(long double)));
+    long double x[2];
 
     memcpy(&x, ptr, sizeof(x));
-    return PyComplex_FromDoubles((double)creall(x), (double)cimagl(x));
+    return PyComplex_FromDoubles((double)x[0], (double)x[1]);
 }
 #endif
 
@@ -1596,7 +1599,7 @@ for base_code, base_c_type in [
     ///////////////////////////////////////////////////////////////////////////
 
     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) {
         TABLE_ENTRY(D, &ffi_type_complex_double);
         TABLE_ENTRY(F, &ffi_type_complex_float);
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 9aceeceb88a49f..2d859ed63e1758 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -11,8 +11,7 @@
 
 // Do we support C99 complex types in ffi?
 // 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)
-#   include "../_complex.h"       // complex
+#if defined(Py_FFI_SUPPORT_C_COMPLEX)
 #   if USING_APPLE_OS_LIBFFI && defined(__has_builtin)
 #       if __has_builtin(__builtin_available)
 #           define Py_FFI_COMPLEX_AVAILABLE __builtin_available(macOS 10.15, *)
@@ -494,11 +493,9 @@ struct tagPyCArgObject {
         double d;
         float f;
         void *p;
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
-        double complex D;
-        float complex F;
-        long double complex G;
-#endif
+        double D[2];
+        float F[2];
+        long double G[2];
     } value;
     PyObject *obj;
     Py_ssize_t size; /* for the 'V' tag */
diff --git a/Modules/_struct.c b/Modules/_struct.c
index e400f607b558dc..c36079f1eb8886 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -853,8 +853,8 @@ static const formatdef native_table[] = {
     {'e',       sizeof(short),  _Alignof(short),    nu_halffloat,   
np_halffloat},
     {'f',       sizeof(float),  _Alignof(float),    nu_float,       np_float},
     {'d',       sizeof(double), _Alignof(double),   nu_double,      np_double},
-    {'F',       2*sizeof(float), _Alignof(float[2]), nu_float_complex, 
np_float_complex},
-    {'D',       2*sizeof(double), _Alignof(double[2]), nu_double_complex, 
np_double_complex},
+    {'F',       2*sizeof(float), _Alignof(float), nu_float_complex, 
np_float_complex},
+    {'D',       2*sizeof(double), _Alignof(double), nu_double_complex, 
np_double_complex},
     {'P',       sizeof(void *), _Alignof(void *),   nu_void_p,      np_void_p},
     {0}
 };

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to