From c9b872f7a1a4052e8b0400a2f2b923f4ea9b2802 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 22 Jun 2024 10:19:26 +0300 Subject: [PATCH 01/55] gh-61103: support double complex (_Complex) type in ctypes Example: ```pycon >>> import ctypes >>> ctypes.__STDC_IEC_559_COMPLEX__ 1 >>> libm = ctypes.CDLL('libm.so.6') >>> libm.clog.argtypes = [ctypes.c_double_complex] >>> libm.clog.restype = ctypes.c_double_complex >>> libm.clog(1+1j) (0.34657359027997264+0.7853981633974483j) ``` ``ctypes.__STDC_IEC_559_COMPLEX__`` is ``0`` if compiler doesn't support complex arithmetic (Annex G). --- Doc/library/ctypes.rst | 11 +++++++ Lib/ctypes/__init__.py | 5 +++ Lib/test/test_ctypes/test_libc.py | 10 ++++++ ...4-06-23-07-23-08.gh-issue-61103.ca_U_l.rst | 2 ++ Modules/_ctypes/_ctypes.c | 22 ++++++++++++- Modules/_ctypes/_ctypes_test.c | 11 +++++++ Modules/_ctypes/cfield.c | 32 +++++++++++++++++++ 7 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 29b35af1c858ee..6ad3cd5963c597 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -266,6 +266,17 @@ Fundamental data types (1) The constructor accepts any object with a truth value. +Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported, following +complex types are available: + ++----------------------------------+---------------------------------+-----------------+ +| ctypes type | C type | Python type | ++==================================+===================================================+ +| :class:`!c_double_complex` | :c:expr:`double complex` | complex | ++----------------------------------+---------------------------------+-----------------+ + + +(1) All these types can be created by calling them with an optional initializer of the correct type and value:: diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index b7ee46d664ab08..e1488c5d0ed4e2 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -12,6 +12,7 @@ from _ctypes import RTLD_LOCAL, RTLD_GLOBAL from _ctypes import ArgumentError from _ctypes import SIZEOF_TIME_T +from _ctypes import __STDC_IEC_559_COMPLEX__ from struct import calcsize as _calcsize @@ -205,6 +206,10 @@ class c_longdouble(_SimpleCData): if sizeof(c_longdouble) == sizeof(c_double): c_longdouble = c_double +if __STDC_IEC_559_COMPLEX__: + class c_double_complex(_SimpleCData): + _type_ = "C" + if _calcsize("l") == _calcsize("q"): # if long and long long have the same size, make c_longlong an alias for c_long c_longlong = c_long diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 7716100b08f78e..0abfe01f024ed2 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -1,3 +1,4 @@ +import ctypes import math import unittest from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, @@ -21,6 +22,15 @@ def test_sqrt(self): self.assertEqual(lib.my_sqrt(4.0), 2.0) self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) + def test_csqrt(self): + lib.my_csqrt.argtypes = ctypes.c_double_complex, + lib.my_csqrt.restype = ctypes.c_double_complex + self.assertEqual(lib.my_csqrt(4.0), 2+0j) + self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) + self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) + + @unittest.skipUnless(ctypes.__STDC_IEC_559_COMPLEX__, + "requires C11 complex type") def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc diff --git a/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst b/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst new file mode 100644 index 00000000000000..bc15a2809cd5c6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst @@ -0,0 +1,2 @@ +Support :c:expr:`double complex` C type in :mod:`ctypes` if compiler has C11 +complex arithmetic. Patch by Sergey B Kirpichev. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 1d9534671a4ee8..914b2b0a9a4791 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1750,7 +1750,11 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ +#ifdef __STDC_IEC_559_COMPLEX__ +static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g"; +#else static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; +#endif /*[clinic input] _ctypes.c_wchar_p.from_param as c_wchar_p_from_param @@ -2226,7 +2230,17 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) goto error; } - stginfo->ffi_type_pointer = *fmt->pffi_type; + if (fmt->pffi_type->type != FFI_TYPE_COMPLEX) { + stginfo->ffi_type_pointer = *fmt->pffi_type; + } + else { + stginfo->ffi_type_pointer.size = fmt->pffi_type->size; + stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment; + stginfo->ffi_type_pointer.type = fmt->pffi_type->type; + stginfo->ffi_type_pointer.elements = PyMem_Malloc(2*sizeof(ffi_type)); + memcpy(stginfo->ffi_type_pointer.elements, + fmt->pffi_type->elements, 2*sizeof(ffi_type)); + } stginfo->align = fmt->pffi_type->alignment; stginfo->length = 0; stginfo->size = fmt->pffi_type->size; @@ -5811,6 +5825,12 @@ _ctypes_add_objects(PyObject *mod) MOD_ADD("_cast_addr", PyLong_FromVoidPtr(cast)); MOD_ADD("_wstring_at_addr", PyLong_FromVoidPtr(wstring_at)); +#ifdef __STDC_IEC_559_COMPLEX__ + MOD_ADD("__STDC_IEC_559_COMPLEX__", PyLong_FromLong(__STDC_IEC_559_COMPLEX__)); +#else + MOD_ADD("__STDC_IEC_559_COMPLEX__", PyLong_FromLong(0)); +#endif + /* If RTLD_LOCAL is not defined (Windows!), set it to zero. */ #if !HAVE_DECL_RTLD_LOCAL # define RTLD_LOCAL 0 diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index e9ff8108efaa2f..ea1a4e1c585ea2 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,6 +13,10 @@ #include +#ifdef __STDC_IEC_559_COMPLEX__ +# include // csqrt() +# undef I +#endif #include // printf() #include // qsort() #include // memset() @@ -443,6 +447,13 @@ EXPORT(double) my_sqrt(double a) return sqrt(a); } +#ifdef __STDC_IEC_559_COMPLEX__ +EXPORT(double complex) my_csqrt(double complex a) +{ + return csqrt(a); +} +#endif + EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*)) { qsort(base, num, width, compare); diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index fa5213ca76d54f..e159df67829f10 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -11,6 +11,10 @@ #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_call.h" // _PyObject_CallNoArgs() +#ifdef __STDC_IEC_559_COMPLEX__ +# include // complex +#endif + #include #include "ctypes.h" @@ -1087,6 +1091,30 @@ d_get(void *ptr, Py_ssize_t size) return PyFloat_FromDouble(val); } +#ifdef __STDC_IEC_559_COMPLEX__ +static PyObject * +C_set(void *ptr, PyObject *value, Py_ssize_t size) +{ + Py_complex c = PyComplex_AsCComplex(value); + double complex x = CMPLX(c.real, c.imag); + + if (c.real == -1 && PyErr_Occurred()) { + return NULL; + } + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +C_get(void *ptr, Py_ssize_t size) +{ + double complex x; + + memcpy(&x, ptr, sizeof(x)); + return PyComplex_FromDoubles(creal(x), cimag(x)); +} +#endif + static PyObject * d_set_sw(void *ptr, PyObject *value, Py_ssize_t size) { @@ -1592,6 +1620,7 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, + { 'C', C_set, C_get, NULL}, { 'g', g_set, g_get, NULL}, { 'f', f_set, f_get, NULL, f_set_sw, f_get_sw}, { 'h', h_set, h_get, NULL, h_set_sw, h_get_sw}, @@ -1642,6 +1671,9 @@ _ctypes_init_fielddesc(void) case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'c': fd->pffi_type = &ffi_type_schar; break; case 'd': fd->pffi_type = &ffi_type_double; break; +#ifdef __STDC_IEC_559_COMPLEX__ + case 'C': fd->pffi_type = &ffi_type_complex_double; break; +#endif case 'g': fd->pffi_type = &ffi_type_longdouble; break; case 'f': fd->pffi_type = &ffi_type_float; break; case 'h': fd->pffi_type = &ffi_type_sshort; break; From b402300dd12ad569dbf0086a0f440da59d34838d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 08:15:35 +0300 Subject: [PATCH 02/55] + ifdef --- Modules/_ctypes/cfield.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index e159df67829f10..adf4ca44d79335 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -1620,7 +1620,9 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, +#ifdef __STDC_IEC_559_COMPLEX__ { 'C', C_set, C_get, NULL}, +#endif { 'g', g_set, g_get, NULL}, { 'f', f_set, f_get, NULL, f_set_sw, f_get_sw}, { 'h', h_set, h_get, NULL, h_set_sw, h_get_sw}, From ad39e6daeff9ba6604ee051117514caab87ccb03 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 08:34:00 +0300 Subject: [PATCH 03/55] + fix rst formatting --- Doc/library/ctypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 6ad3cd5963c597..24f9672a970b8b 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -271,7 +271,7 @@ complex types are available: +----------------------------------+---------------------------------+-----------------+ | ctypes type | C type | Python type | -+==================================+===================================================+ ++==================================+=================================+=================+ | :class:`!c_double_complex` | :c:expr:`double complex` | complex | +----------------------------------+---------------------------------+-----------------+ From fd9135b4840e8f726710f66de231ce8aae91e8c2 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 08:57:56 +0300 Subject: [PATCH 04/55] + CMPLX --- Modules/_ctypes/cfield.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index adf4ca44d79335..98fbb8a1a6e933 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -1092,6 +1092,10 @@ d_get(void *ptr, Py_ssize_t size) } #ifdef __STDC_IEC_559_COMPLEX__ +#if defined(__clang__) && __has_builtin(__builtin_complex) && \ + !defined(CMPLX) +# define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y)) +#endif static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { From c296fb379e4a591639a7d438f6131e9cb71ba264 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 09:00:45 +0300 Subject: [PATCH 05/55] Apply suggestions from code review Co-authored-by: Nice Zombies --- Lib/test/test_ctypes/test_libc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 0abfe01f024ed2..456aa66673ea8d 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -22,6 +22,8 @@ def test_sqrt(self): self.assertEqual(lib.my_sqrt(4.0), 2.0) self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) + @unittest.skipUnless(ctypes.__STDC_IEC_559_COMPLEX__, + "requires C11 complex type") def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex @@ -29,8 +31,6 @@ def test_csqrt(self): self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) - @unittest.skipUnless(ctypes.__STDC_IEC_559_COMPLEX__, - "requires C11 complex type") def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc From 7453ca567df52862b412839fa1a63d0c06fde3d1 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 10:11:26 +0300 Subject: [PATCH 06/55] + support _Complex in c-analyzer --- Tools/c-analyzer/c_parser/parser/_regexes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tools/c-analyzer/c_parser/parser/_regexes.py b/Tools/c-analyzer/c_parser/parser/_regexes.py index 5695daff67d6bd..025194a84f8c89 100644 --- a/Tools/c-analyzer/c_parser/parser/_regexes.py +++ b/Tools/c-analyzer/c_parser/parser/_regexes.py @@ -72,6 +72,7 @@ def _ind(text, level=1, edges='both'): long | float | double | + _Complex | void | struct | @@ -121,6 +122,11 @@ def _ind(text, level=1, edges='both'): | (?: signed | unsigned ) # implies int | + (?: + (?: (?: float | double ) \s+ )? + _Complex + ) + | (?: (?: (?: signed | unsigned ) \s+ )? (?: (?: long | short ) \s+ )? From e444c9ce8550cb8f19d37042f3322f71ff4ba0bb Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 10:47:22 +0300 Subject: [PATCH 07/55] +1 --- Tools/c-analyzer/c_parser/parser/_regexes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/c-analyzer/c_parser/parser/_regexes.py b/Tools/c-analyzer/c_parser/parser/_regexes.py index 025194a84f8c89..e44c56fea46d5f 100644 --- a/Tools/c-analyzer/c_parser/parser/_regexes.py +++ b/Tools/c-analyzer/c_parser/parser/_regexes.py @@ -123,7 +123,7 @@ def _ind(text, level=1, edges='both'): (?: signed | unsigned ) # implies int | (?: - (?: (?: float | double ) \s+ )? + (?: (?: float | double | long\s+double ) \s+ )? _Complex ) | From 2e90643f609f029fa146fc86a503728cb6a29235 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 10:47:40 +0300 Subject: [PATCH 08/55] expand docs --- Doc/library/ctypes.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 24f9672a970b8b..f617c65012120b 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -272,7 +272,7 @@ complex types are available: +----------------------------------+---------------------------------+-----------------+ | ctypes type | C type | Python type | +==================================+=================================+=================+ -| :class:`!c_double_complex` | :c:expr:`double complex` | complex | +| :class:`c_double_complex` | :c:expr:`double complex` | complex | +----------------------------------+---------------------------------+-----------------+ @@ -2295,6 +2295,12 @@ These are the fundamental ctypes data types: optional float initializer. +.. class:: c_double_complex + + Represents the C :c:expr:`double complex` datatype, if it's available. The + constructor accepts an optional :class:`complex` initializer. + + .. class:: c_int Represents the C :c:expr:`signed int` datatype. The constructor accepts an From 32ffacf690ac2dfa67e4cd38c15b14d6d007f4d0 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 11:18:01 +0300 Subject: [PATCH 09/55] drop ctypes.__STDC_IEC_559_COMPLEX__ --- Lib/ctypes/__init__.py | 5 +++-- Lib/test/test_ctypes/test_libc.py | 2 +- Modules/_ctypes/_ctypes.c | 6 ------ 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index e1488c5d0ed4e2..d2e6a8bfc8c9d4 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -12,7 +12,6 @@ from _ctypes import RTLD_LOCAL, RTLD_GLOBAL from _ctypes import ArgumentError from _ctypes import SIZEOF_TIME_T -from _ctypes import __STDC_IEC_559_COMPLEX__ from struct import calcsize as _calcsize @@ -206,9 +205,11 @@ class c_longdouble(_SimpleCData): if sizeof(c_longdouble) == sizeof(c_double): c_longdouble = c_double -if __STDC_IEC_559_COMPLEX__: +try: class c_double_complex(_SimpleCData): _type_ = "C" +except AttributeError: + pass if _calcsize("l") == _calcsize("q"): # if long and long long have the same size, make c_longlong an alias for c_long diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 456aa66673ea8d..168833fe3a3805 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -22,7 +22,7 @@ def test_sqrt(self): self.assertEqual(lib.my_sqrt(4.0), 2.0) self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) - @unittest.skipUnless(ctypes.__STDC_IEC_559_COMPLEX__, + @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 914b2b0a9a4791..61c7fc3bd7360a 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5825,12 +5825,6 @@ _ctypes_add_objects(PyObject *mod) MOD_ADD("_cast_addr", PyLong_FromVoidPtr(cast)); MOD_ADD("_wstring_at_addr", PyLong_FromVoidPtr(wstring_at)); -#ifdef __STDC_IEC_559_COMPLEX__ - MOD_ADD("__STDC_IEC_559_COMPLEX__", PyLong_FromLong(__STDC_IEC_559_COMPLEX__)); -#else - MOD_ADD("__STDC_IEC_559_COMPLEX__", PyLong_FromLong(0)); -#endif - /* If RTLD_LOCAL is not defined (Windows!), set it to zero. */ #if !HAVE_DECL_RTLD_LOCAL # define RTLD_LOCAL 0 From 9163950ef146f32ff200d3f9bbd9b38c7cbed40d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 12:34:26 +0300 Subject: [PATCH 10/55] And more tests, finally) --- Lib/test/test_ctypes/test_numbers.py | 49 ++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index 29108a28ec16e1..989c9a417ac71a 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -1,4 +1,5 @@ import array +import ctypes import struct import sys import unittest @@ -7,6 +8,10 @@ c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, c_longdouble, c_bool) +try: + from ctypes import c_double_complex +except ImportError: + pass def valid_ranges(*types): @@ -38,6 +43,22 @@ def valid_ranges(*types): signed_ranges = valid_ranges(*signed_types) bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]] +class IntLike: + def __int__(self): + return 2 + +class IndexLike: + def __index__(self): + return 2 + +class FloatLike: + def __float__(self): + return 2.0 + +class ComplexLike: + def __complex__(self): + return 1+1j + class NumberTestCase(unittest.TestCase): @@ -82,13 +103,9 @@ def test_byref(self): parm = byref(t()) self.assertEqual(ArgType, type(parm)) - def test_floats(self): # c_float and c_double can be created from # Python int and float - class FloatLike: - def __float__(self): - return 2.0 f = FloatLike() for t in float_types: self.assertEqual(t(2.0).value, 2.0) @@ -96,18 +113,24 @@ def __float__(self): self.assertEqual(t(2).value, 2.0) self.assertEqual(t(f).value, 2.0) + @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), + "requires C11 complex type") + def test_complex(self): + i = IndexLike() + f = FloatLike() + c = ComplexLike() + + for t in [c_double_complex]: + self.assertEqual(t(1).value, 1+0j) + self.assertEqual(t(1.0).value, 1+0j) + self.assertEqual(t(1+1j).value, 1+1j) + self.assertEqual(t(i).value, 2+0j) + self.assertEqual(t(f).value, 2+0j) + self.assertEqual(t(c).value, 1+1j) + def test_integers(self): - class FloatLike: - def __float__(self): - return 2.0 f = FloatLike() - class IntLike: - def __int__(self): - return 2 d = IntLike() - class IndexLike: - def __index__(self): - return 2 i = IndexLike() # integers cannot be constructed from floats, # but from integer-like objects From bf816828837c3fe6f21b8b75c3504081f11c68fe Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 13:26:12 +0300 Subject: [PATCH 11/55] Apply suggestions from code review Co-authored-by: Nice Zombies --- Doc/library/ctypes.rst | 3 ++- Lib/test/test_ctypes/test_numbers.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index f617c65012120b..125ce916ba935d 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -276,7 +276,6 @@ complex types are available: +----------------------------------+---------------------------------+-----------------+ -(1) All these types can be created by calling them with an optional initializer of the correct type and value:: @@ -2300,6 +2299,8 @@ These are the fundamental ctypes data types: Represents the C :c:expr:`double complex` datatype, if it's available. The constructor accepts an optional :class:`complex` initializer. + .. versionadded:: 3.14 + .. class:: c_int diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index 989c9a417ac71a..ade7f54689b7dd 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -103,6 +103,7 @@ def test_byref(self): parm = byref(t()) self.assertEqual(ArgType, type(parm)) + def test_floats(self): # c_float and c_double can be created from # Python int and float From af2fdce95fbc9d9d5b16a1423a5a7b014de92c32 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 14:47:24 +0300 Subject: [PATCH 12/55] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/ctypes.rst | 4 ++-- .../Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 125ce916ba935d..a56e0eef5d11b1 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -266,7 +266,7 @@ Fundamental data types (1) The constructor accepts any object with a truth value. -Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported, following +Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported, the following complex types are available: +----------------------------------+---------------------------------+-----------------+ @@ -2296,7 +2296,7 @@ These are the fundamental ctypes data types: .. class:: c_double_complex - Represents the C :c:expr:`double complex` datatype, if it's available. The + Represents the C :c:expr:`double complex` datatype, if available. The constructor accepts an optional :class:`complex` initializer. .. versionadded:: 3.14 diff --git a/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst b/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst index bc15a2809cd5c6..7b11d8c303c2f6 100644 --- a/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst +++ b/Misc/NEWS.d/next/Library/2024-06-23-07-23-08.gh-issue-61103.ca_U_l.rst @@ -1,2 +1,3 @@ -Support :c:expr:`double complex` C type in :mod:`ctypes` if compiler has C11 -complex arithmetic. Patch by Sergey B Kirpichev. +Support :c:expr:`double complex` C type in :mod:`ctypes` via +:class:`~ctypes.c_double_complex` if compiler has C11 complex +arithmetic. Patch by Sergey B Kirpichev. From 6d9d5ab1155fc5ec9a8cacfe01efbce736071cf2 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 15:22:45 +0300 Subject: [PATCH 13/55] + allow _Complex specifier before float/double/etc --- Tools/c-analyzer/c_parser/parser/_regexes.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tools/c-analyzer/c_parser/parser/_regexes.py b/Tools/c-analyzer/c_parser/parser/_regexes.py index e44c56fea46d5f..c1a8ab3ad2f15d 100644 --- a/Tools/c-analyzer/c_parser/parser/_regexes.py +++ b/Tools/c-analyzer/c_parser/parser/_regexes.py @@ -127,6 +127,11 @@ def _ind(text, level=1, edges='both'): _Complex ) | + (?: + _Complex + (?: \s+ (?: float | double | long\s+double ) )? + ) + | (?: (?: (?: signed | unsigned ) \s+ )? (?: (?: long | short ) \s+ )? From f9c709cecef3813e51f537310a466ed01c08c02d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 23 Jun 2024 15:50:25 +0300 Subject: [PATCH 14/55] + comment on clang workaround --- Modules/_ctypes/cfield.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 98fbb8a1a6e933..b3480ee39da18f 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -1092,10 +1092,32 @@ d_get(void *ptr, Py_ssize_t size) } #ifdef __STDC_IEC_559_COMPLEX__ -#if defined(__clang__) && __has_builtin(__builtin_complex) && \ - !defined(CMPLX) -# define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y)) -#endif +/* 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)) +# else +inline double complex +CMPLX(double real, imag) +{ + double complex z; + ((double *)(&z))[0] = real; + ((double *)(&z))[1] = imag; + return z; +} +# endif +# endif static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { From ccd418d9fd666445b61ee2a93482ff8a61045fcf Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 06:44:53 +0300 Subject: [PATCH 15/55] Address review: * add configure test for _Complex type * define HAVE_C_COMPLEX * move workarounds for buggy implementations to Module/_complex.h --- Modules/_complex.h | 32 ++++++++++++++++++++++++++++++ Modules/_ctypes/_ctypes.c | 2 +- Modules/_ctypes/_ctypes_test.c | 6 +++--- Modules/_ctypes/cfield.c | 36 +++++----------------------------- configure | 36 ++++++++++++++++++++++++++++++++++ configure.ac | 20 +++++++++++++++++++ pyconfig.h.in | 3 +++ 7 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 Modules/_complex.h diff --git a/Modules/_complex.h b/Modules/_complex.h new file mode 100644 index 00000000000000..f6b49e10da5ea9 --- /dev/null +++ b/Modules/_complex.h @@ -0,0 +1,32 @@ +/* Workarounds for buggy complex number arithmetic implementations. + If HAVE_C_COMPLEX is defined, you can include this file + instead of . */ + +#include + +/* 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)) +# else +inline double complex +CMPLX(double real, imag) +{ + double complex z; + ((double *)(&z))[0] = real; + ((double *)(&z))[1] = imag; + return z; +} +# endif +#endif diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 61c7fc3bd7360a..44a87e8a080b2d 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1750,7 +1750,7 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ -#ifdef __STDC_IEC_559_COMPLEX__ +#ifdef HAVE_C_COMPLEX static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g"; #else static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index ea1a4e1c585ea2..ac608062c85a65 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,8 +13,8 @@ #include -#ifdef __STDC_IEC_559_COMPLEX__ -# include // csqrt() +#ifdef HAVE_C_COMPLEX +# include "../_complex.h" // csqrt() # undef I #endif #include // printf() @@ -447,7 +447,7 @@ EXPORT(double) my_sqrt(double a) return sqrt(a); } -#ifdef __STDC_IEC_559_COMPLEX__ +#ifdef HAVE_C_COMPLEX EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index b3480ee39da18f..5a0a0948731652 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -11,8 +11,8 @@ #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_call.h" // _PyObject_CallNoArgs() -#ifdef __STDC_IEC_559_COMPLEX__ -# include // complex +#ifdef HAVE_C_COMPLEX +# include "../_complex.h" // complex #endif #include @@ -1091,33 +1091,7 @@ d_get(void *ptr, Py_ssize_t size) return PyFloat_FromDouble(val); } -#ifdef __STDC_IEC_559_COMPLEX__ -/* 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)) -# else -inline double complex -CMPLX(double real, imag) -{ - double complex z; - ((double *)(&z))[0] = real; - ((double *)(&z))[1] = imag; - return z; -} -# endif -# endif +#ifdef HAVE_C_COMPLEX static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { @@ -1646,7 +1620,7 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, -#ifdef __STDC_IEC_559_COMPLEX__ +#ifdef HAVE_C_COMPLEX { 'C', C_set, C_get, NULL}, #endif { 'g', g_set, g_get, NULL}, @@ -1699,7 +1673,7 @@ _ctypes_init_fielddesc(void) case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'c': fd->pffi_type = &ffi_type_schar; break; case 'd': fd->pffi_type = &ffi_type_double; break; -#ifdef __STDC_IEC_559_COMPLEX__ +#ifdef HAVE_C_COMPLEX case 'C': fd->pffi_type = &ffi_type_complex_double; break; #endif case 'g': fd->pffi_type = &ffi_type_longdouble; break; diff --git a/configure b/configure index 0f7ea7dfb5259d..e11081d6cdcbbc 100755 --- a/configure +++ b/configure @@ -13845,6 +13845,42 @@ printf "%s\n" "$AIX_BUILDDATE" >&6; } *) ;; esac +# check for _Complex C type +# +# Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost +# none properly support C11+ Annex G (where imaginary types are mandatory). +# This is a bug, so we don't rely on presence of __STDC_IEC_559_COMPLEX__. +if test "$cross_compiling" = yes +then : + ac_cv_c_complex_supported=no +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +int main(void) +{ + double _Complex z = 1 + _Complex_I*2; + z = z + _Complex_I*z; + return (creal(z) != -1) || (cimag(z) != 3); +} +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + ac_cv_c_complex_supported=yes +else $as_nop + ac_cv_c_complex_supported=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +if test "$ac_cv_c_complex_supported" = "yes"; then + +printf "%s\n" "#define HAVE_C_COMPLEX 1" >>confdefs.h + +fi + # check for systems that require aligned memory access { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking aligned memory access is required" >&5 printf %s "checking aligned memory access is required... " >&6; } diff --git a/configure.ac b/configure.ac index a4698451465155..fb588afb40949a 100644 --- a/configure.ac +++ b/configure.ac @@ -3763,6 +3763,26 @@ dnl The AIX_BUILDDATE is obtained from the kernel fileset - bos.mp64 *) ;; esac +# check for _Complex C type +# +# Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost +# none properly support C11+ Annex G (where imaginary types are mandatory). +# This is a bug, so we don't rely on presence of __STDC_IEC_559_COMPLEX__. +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +int main(void) +{ + double _Complex z = 1 + _Complex_I*2; + z = z + _Complex_I*z; + return (creal(z) != -1) || (cimag(z) != 3); +}]])], [ac_cv_c_complex_supported=yes], +[ac_cv_c_complex_supported=no], +[ac_cv_c_complex_supported=no]) +if test "$ac_cv_c_complex_supported" = "yes"; then + AC_DEFINE([HAVE_C_COMPLEX], [1], + [Defined if _Complex C type is available.]) +fi + # check for systems that require aligned memory access AC_CACHE_CHECK([aligned memory access is required], [ac_cv_aligned_required], [AC_RUN_IFELSE([AC_LANG_SOURCE([[ diff --git a/pyconfig.h.in b/pyconfig.h.in index c279b147db3bdd..e5d0c7a7b92b8b 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -223,6 +223,9 @@ /* Define if you have the 'wchgat' function. */ #undef HAVE_CURSES_WCHGAT +/* Defined if _Complex C type is available. */ +#undef HAVE_C_COMPLEX + /* Define to 1 if you have the header file. */ #undef HAVE_DB_H From eb313dc342bbc4fdeef87724be5f02d642f845dd Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 07:15:13 +0300 Subject: [PATCH 16/55] + @requires_IEEE_754 for test_csqrt() --- Lib/test/test_ctypes/test_libc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 168833fe3a3805..ef4871cc0123ee 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -3,7 +3,7 @@ import unittest from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, c_void_p, c_char, c_int, c_double, c_size_t) -from test.support import import_helper +from test.support import import_helper, requires_IEEE_754 _ctypes_test = import_helper.import_module("_ctypes_test") @@ -24,6 +24,7 @@ def test_sqrt(self): @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") + @requires_IEEE_754 def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex From 693c04efa33d004430a2a7e12872e0092ef708d9 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 07:30:05 +0300 Subject: [PATCH 17/55] Revert "+ @requires_IEEE_754 for test_csqrt()" This reverts commit eb313dc342bbc4fdeef87724be5f02d642f845dd. --- Lib/test/test_ctypes/test_libc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index ef4871cc0123ee..168833fe3a3805 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -3,7 +3,7 @@ import unittest from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, c_void_p, c_char, c_int, c_double, c_size_t) -from test.support import import_helper, requires_IEEE_754 +from test.support import import_helper _ctypes_test = import_helper.import_module("_ctypes_test") @@ -24,7 +24,6 @@ def test_sqrt(self): @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") - @requires_IEEE_754 def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex From 0ee70497567e946bafa8d391c5e01959cca86f1e Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 07:34:01 +0300 Subject: [PATCH 18/55] Adjust test_csqrt() to not use special numbers --- Lib/test/test_ctypes/test_libc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 168833fe3a3805..e1790877169ce3 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,8 +28,10 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) - self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) - self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) + self.assertAlmostEqual(lib.my_csqrt(-1+0.01j), + 0.004999937502734214+1.0000124996093955j) + self.assertAlmostEqual(lib.my_csqrt(-1-0.01j), + 0.004999937502734214-1.0000124996093955j) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) From de91bbe66aa605fa48dd105e2330ea71210e325b Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 07:53:39 +0300 Subject: [PATCH 19/55] Revert "Adjust test_csqrt() to not use special numbers" This reverts commit 0ee70497567e946bafa8d391c5e01959cca86f1e. --- Lib/test/test_ctypes/test_libc.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index e1790877169ce3..168833fe3a3805 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,10 +28,8 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) - self.assertAlmostEqual(lib.my_csqrt(-1+0.01j), - 0.004999937502734214+1.0000124996093955j) - self.assertAlmostEqual(lib.my_csqrt(-1-0.01j), - 0.004999937502734214-1.0000124996093955j) + self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) + self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) From b79200ee96fa2744c2bd7419ae2f5a42b1e61ec2 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 08:01:07 +0300 Subject: [PATCH 20/55] +1 --- Lib/test/test_ctypes/test_libc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 168833fe3a3805..d7805e673a3053 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,8 +28,10 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) - self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) - self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) + self.assertAlmostEqual(lib.my_csqrt(1+1j), + 1.09868411346781+0.45508986056222733j) + self.assertAlmostEqual(lib.my_csqrt(1-1j), + 1.09868411346781-0.45508986056222733j) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) From be6a685469a36a7e77ea9e1524aa99c43d1b3380 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 08:15:32 +0300 Subject: [PATCH 21/55] +1 --- Lib/test/test_ctypes/test_libc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index d7805e673a3053..370abbd4e04d5b 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -27,7 +27,7 @@ def test_sqrt(self): def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex - self.assertEqual(lib.my_csqrt(4.0), 2+0j) + self.assertAlmostEqual(lib.my_csqrt(4.0), 2+0j) self.assertAlmostEqual(lib.my_csqrt(1+1j), 1.09868411346781+0.45508986056222733j) self.assertAlmostEqual(lib.my_csqrt(1-1j), From 04e89c224faa4fa42798fc641a4534fb61633811 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 10:17:39 +0300 Subject: [PATCH 22/55] revert test + fix typo --- Lib/test/test_ctypes/test_libc.py | 8 +++----- Modules/_complex.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 370abbd4e04d5b..168833fe3a3805 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -27,11 +27,9 @@ def test_sqrt(self): def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex - self.assertAlmostEqual(lib.my_csqrt(4.0), 2+0j) - self.assertAlmostEqual(lib.my_csqrt(1+1j), - 1.09868411346781+0.45508986056222733j) - self.assertAlmostEqual(lib.my_csqrt(1-1j), - 1.09868411346781-0.45508986056222733j) + self.assertEqual(lib.my_csqrt(4.0), 2+0j) + self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) + self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) diff --git a/Modules/_complex.h b/Modules/_complex.h index f6b49e10da5ea9..429af54a3605b8 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -21,7 +21,7 @@ # define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y)) # else inline double complex -CMPLX(double real, imag) +CMPLX(double real, double imag) { double complex z; ((double *)(&z))[0] = real; From 0bc87dab58e17e9a1cc5272af1a7ac975bd63058 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 07:34:01 +0300 Subject: [PATCH 23/55] Adjust test_csqrt() to not use special numbers --- Lib/test/test_ctypes/test_libc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 168833fe3a3805..e1790877169ce3 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,8 +28,10 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) - self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) - self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) + self.assertAlmostEqual(lib.my_csqrt(-1+0.01j), + 0.004999937502734214+1.0000124996093955j) + self.assertAlmostEqual(lib.my_csqrt(-1-0.01j), + 0.004999937502734214-1.0000124996093955j) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) From 634741203e796d57a84abc1e6a887b87751d7dbf Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 10:54:06 +0300 Subject: [PATCH 24/55] + make CMPLX static --- Modules/_complex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_complex.h b/Modules/_complex.h index 429af54a3605b8..4923424d883c81 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -20,7 +20,7 @@ # if defined(__clang__) && __has_builtin(__builtin_complex) # define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y)) # else -inline double complex +static double complex CMPLX(double real, double imag) { double complex z; From e757fb6812c3c9d88b80df3cebff11d150615f0c Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 11:05:03 +0300 Subject: [PATCH 25/55] try bad CMPLX() --- Modules/_complex.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Modules/_complex.h b/Modules/_complex.h index 4923424d883c81..82fd563ae8e2cf 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -23,10 +23,7 @@ static double complex CMPLX(double real, double imag) { - double complex z; - ((double *)(&z))[0] = real; - ((double *)(&z))[1] = imag; - return z; + return real + imag*_Complex_I; } # endif #endif From 1eb989cdbbddbc7481b9e605f3a35bad60cc41f3 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 11:23:28 +0300 Subject: [PATCH 26/55] more tests --- Lib/test/test_ctypes/test_libc.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index e1790877169ce3..6308e9edf47c23 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,6 +28,10 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) + self.assertAlmostEqual(lib.my_csqrt(1+0.01j), + 1.000000124999961+0.0004999999375000273j) + self.assertAlmostEqual(lib.my_csqrt(1-0.01j), + 1.000000124999961-0.0004999999375000273j) self.assertAlmostEqual(lib.my_csqrt(-1+0.01j), 0.004999937502734214+1.0000124996093955j) self.assertAlmostEqual(lib.my_csqrt(-1-0.01j), From b44aae23c79a5e365941e8a7cf4c8164c4d13bf1 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 11:36:11 +0300 Subject: [PATCH 27/55] cexp test --- Lib/test/test_ctypes/test_libc.py | 12 ++++-------- Modules/_ctypes/_ctypes_test.c | 4 ++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 6308e9edf47c23..9c269201adff52 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,14 +28,10 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) - self.assertAlmostEqual(lib.my_csqrt(1+0.01j), - 1.000000124999961+0.0004999999375000273j) - self.assertAlmostEqual(lib.my_csqrt(1-0.01j), - 1.000000124999961-0.0004999999375000273j) - self.assertAlmostEqual(lib.my_csqrt(-1+0.01j), - 0.004999937502734214+1.0000124996093955j) - self.assertAlmostEqual(lib.my_csqrt(-1-0.01j), - 0.004999937502734214-1.0000124996093955j) + lib.my_cexp.argtypes = ctypes.c_double_complex, + lib.my_cexp.restype = ctypes.c_double_complex + self.assertAlmostEqual(lib.my_cexp(1+1j), + 1.4686939399158851+2.2873552871788423j) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index ac608062c85a65..74ebce1356365c 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -452,6 +452,10 @@ EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); } +EXPORT(double complex) my_cexp(double complex a) +{ + return cexp(a); +} #endif EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*)) From 215360811ffdfb087e70bd7d576a598b1ff9e338 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 12:06:41 +0300 Subject: [PATCH 28/55] use my_csquare() in test --- Lib/test/test_ctypes/test_libc.py | 7 +++---- Modules/_ctypes/_ctypes_test.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 9c269201adff52..51d7d7acf4d3c7 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,10 +28,9 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) - lib.my_cexp.argtypes = ctypes.c_double_complex, - lib.my_cexp.restype = ctypes.c_double_complex - self.assertAlmostEqual(lib.my_cexp(1+1j), - 1.4686939399158851+2.2873552871788423j) + lib.my_csquare.argtypes = ctypes.c_double_complex, + lib.my_csquare.restype = ctypes.c_double_complex + self.assertEqual(lib.my_csquare(1+2j), -3+4j) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 74ebce1356365c..c59d9c0cf825b5 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -452,9 +452,9 @@ EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); } -EXPORT(double complex) my_cexp(double complex a) +EXPORT(double complex) my_csquare(double complex a) { - return cexp(a); + return a*a; } #endif From af42aa8c9c77317c4faebc68f224fdf62e3b6c27 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 12:15:24 +0300 Subject: [PATCH 29/55] revert CMPLX --- Modules/_complex.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/_complex.h b/Modules/_complex.h index 82fd563ae8e2cf..c96ee9c838fd7d 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -20,10 +20,13 @@ # if defined(__clang__) && __has_builtin(__builtin_complex) # define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y)) # else -static double complex +static inline double complex CMPLX(double real, double imag) { - return real + imag*_Complex_I; + double complex z; + ((double *)(&z))[0] = real; + ((double *)(&z))[1] = imag; + return z; } # endif #endif From e57198e1d94a111129524a84cbbb31631d2c106f Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 12:20:20 +0300 Subject: [PATCH 30/55] Address review: * cleanup test_ctypes/test_numbers.py * rewort comment in configure.ac, add issue link --- Lib/test/test_ctypes/test_numbers.py | 12 ++++-------- configure | 6 ++++-- configure.ac | 6 ++++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index ade7f54689b7dd..47a9f5d37bf73c 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -117,17 +117,13 @@ def test_floats(self): @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") def test_complex(self): - i = IndexLike() - f = FloatLike() - c = ComplexLike() - for t in [c_double_complex]: self.assertEqual(t(1).value, 1+0j) self.assertEqual(t(1.0).value, 1+0j) - self.assertEqual(t(1+1j).value, 1+1j) - self.assertEqual(t(i).value, 2+0j) - self.assertEqual(t(f).value, 2+0j) - self.assertEqual(t(c).value, 1+1j) + self.assertEqual(t(1+0.125j).value, 1+0.125j) + self.assertEqual(t(IndexLike()).value, 2+0j) + self.assertEqual(t(FloatLike()).value, 2+0j) + self.assertEqual(t(ComplexLike()).value, 1+1j) def test_integers(self): f = FloatLike() diff --git a/configure b/configure index e11081d6cdcbbc..dc8a176e02669a 100755 --- a/configure +++ b/configure @@ -13848,8 +13848,10 @@ esac # check for _Complex C type # # Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost -# none properly support C11+ Annex G (where imaginary types are mandatory). -# This is a bug, so we don't rely on presence of __STDC_IEC_559_COMPLEX__. +# none properly support C11+ Annex G (where pure imaginary types +# represented by _Imaginary are mandatory). This is a bug (see e.g. +# llvm/llvm-project#60269), so we don't rely on presence +# of __STDC_IEC_559_COMPLEX__. if test "$cross_compiling" = yes then : ac_cv_c_complex_supported=no diff --git a/configure.ac b/configure.ac index fb588afb40949a..1bb29a32d88223 100644 --- a/configure.ac +++ b/configure.ac @@ -3766,8 +3766,10 @@ esac # check for _Complex C type # # Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost -# none properly support C11+ Annex G (where imaginary types are mandatory). -# This is a bug, so we don't rely on presence of __STDC_IEC_559_COMPLEX__. +# none properly support C11+ Annex G (where pure imaginary types +# represented by _Imaginary are mandatory). This is a bug (see e.g. +# llvm/llvm-project#60269), so we don't rely on presence +# of __STDC_IEC_559_COMPLEX__. AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main(void) From 36732bc2fc79cce980cc20d1d9489d5f651e6abe Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 12:33:41 +0300 Subject: [PATCH 31/55] revert tests --- Lib/test/test_ctypes/test_libc.py | 5 ++--- Modules/_ctypes/_ctypes_test.c | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 51d7d7acf4d3c7..168833fe3a3805 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,9 +28,8 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4.0), 2+0j) - lib.my_csquare.argtypes = ctypes.c_double_complex, - lib.my_csquare.restype = ctypes.c_double_complex - self.assertEqual(lib.my_csquare(1+2j), -3+4j) + self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) + self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index c59d9c0cf825b5..ac608062c85a65 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -452,10 +452,6 @@ EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); } -EXPORT(double complex) my_csquare(double complex a) -{ - return a*a; -} #endif EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*)) From 892b2414536108ed5b713391210f7dc4c1f0f488 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 12:38:54 +0300 Subject: [PATCH 32/55] XXX skip test on MacOs arm64 --- Lib/test/test_ctypes/test_libc.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 168833fe3a3805..de1253ef608410 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -1,6 +1,8 @@ import ctypes import math +import platform import unittest +import sys from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, c_void_p, c_char, c_int, c_double, c_size_t) from test.support import import_helper @@ -24,6 +26,8 @@ def test_sqrt(self): @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") + @unittest.skipIf(sys.platform == 'darwin' + and platform.machine() == 'ARM64', "TODO") def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex From ee953c35bb1ba6b4d6b4b6013e8187f4d0b195bd Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 12:47:02 +0300 Subject: [PATCH 33/55] Revert "XXX skip test on MacOs arm64" This reverts commit 892b2414536108ed5b713391210f7dc4c1f0f488. --- Lib/test/test_ctypes/test_libc.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index de1253ef608410..168833fe3a3805 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -1,8 +1,6 @@ import ctypes import math -import platform import unittest -import sys from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, c_void_p, c_char, c_int, c_double, c_size_t) from test.support import import_helper @@ -26,8 +24,6 @@ def test_sqrt(self): @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") - @unittest.skipIf(sys.platform == 'darwin' - and platform.machine() == 'ARM64', "TODO") def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex From 875cbb82affa2fcb67259a8d87ebf84e3b002931 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 12:48:43 +0300 Subject: [PATCH 34/55] XXX (to pass) --- Lib/test/test_ctypes/test_libc.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 168833fe3a3805..a4655525a832c5 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -27,9 +27,8 @@ def test_sqrt(self): def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex - self.assertEqual(lib.my_csqrt(4.0), 2+0j) - self.assertEqual(lib.my_csqrt(complex(-1, +0.)), complex(0, +1)) - self.assertEqual(lib.my_csqrt(complex(-1, -0.)), complex(0, -1)) + self.assertEqual(lib.my_csqrt(4), 2+0j) + self.assertEqual(lib.my_csqrt(-1), 1j) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) From f8e3a47691c4ce133381497855317b97a1b87b03 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 13:07:14 +0300 Subject: [PATCH 35/55] Address review: guard _complex.h with ifndef --- Modules/_complex.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Modules/_complex.h b/Modules/_complex.h index c96ee9c838fd7d..d973ee3b0e2efb 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -1,6 +1,8 @@ -/* Workarounds for buggy complex number arithmetic implementations. - If HAVE_C_COMPLEX is defined, you can include this file - instead of . */ +/* Workarounds for buggy complex number arithmetic implementations. */ + +#ifndef HAVE_C_COMPLEX +# error "this header file should be included if HAVE_C_COMPLEX is defined" +#endif #include From f447919955cf093bde045d10cf426863845c3b99 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 14:07:43 +0300 Subject: [PATCH 36/55] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Modules/_complex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_complex.h b/Modules/_complex.h index d973ee3b0e2efb..4e66a4152e4056 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -1,7 +1,7 @@ /* Workarounds for buggy complex number arithmetic implementations. */ #ifndef HAVE_C_COMPLEX -# error "this header file should be included if HAVE_C_COMPLEX is defined" +# error "this header file should only be included if HAVE_C_COMPLEX is defined" #endif #include From 2ea028acd710d4ce887289757fd321aa5e792da0 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 25 Jun 2024 12:16:54 +0300 Subject: [PATCH 37/55] Add _Complex (sic!) to union result --- Modules/_ctypes/callproc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index cbed2f32caa6c4..5078058a253796 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -651,6 +651,7 @@ union result { double d; float f; void *p; + double _Complex C; }; struct argument { From 837add46df3cc19617caaef34cdb77c42d08f35a Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 25 Jun 2024 12:25:26 +0300 Subject: [PATCH 38/55] add missing ifdef + restore tests --- Lib/test/test_ctypes/test_libc.py | 3 ++- Modules/_ctypes/callproc.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index a4655525a832c5..a817311114eb69 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,7 +28,8 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4), 2+0j) - self.assertEqual(lib.my_csqrt(-1), 1j) + self.assertEqual(lib.my_csqrt(complex(-1, +0.0)), complex(0, +1)) + self.assertEqual(lib.my_csqrt(complex(-1, -0.0)), complex(0, -1)) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 5078058a253796..27b4dd4b9ce359 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -651,7 +651,9 @@ union result { double d; float f; void *p; +#ifdef HAVE_C_COMPLEX double _Complex C; +#endif }; struct argument { From 1b8f37e38de52e7aa0aca0bc634b3ddeef282bd8 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 24 Jun 2024 07:34:01 +0300 Subject: [PATCH 39/55] Adjust test_csqrt() to not use special numbers --- Lib/test/test_ctypes/test_libc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index a817311114eb69..dec0afff4b38fd 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -28,8 +28,10 @@ def test_csqrt(self): lib.my_csqrt.argtypes = ctypes.c_double_complex, lib.my_csqrt.restype = ctypes.c_double_complex self.assertEqual(lib.my_csqrt(4), 2+0j) - self.assertEqual(lib.my_csqrt(complex(-1, +0.0)), complex(0, +1)) - self.assertEqual(lib.my_csqrt(complex(-1, -0.0)), complex(0, -1)) + self.assertAlmostEqual(lib.my_csqrt(-1+0.01j), + 0.004999937502734214+1.0000124996093955j) + self.assertAlmostEqual(lib.my_csqrt(-1-0.01j), + 0.004999937502734214-1.0000124996093955j) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) From 0bd1ebe0f5ca2e5052e373d2184294c80ece52f7 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 25 Jun 2024 12:58:16 +0300 Subject: [PATCH 40/55] Add _Complex also to tagPyCArgObject struct --- Modules/_ctypes/ctypes.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 2d711dabab6c77..e004e128db8db1 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -393,6 +393,9 @@ struct tagPyCArgObject { double d; float f; void *p; +#ifdef HAVE_C_COMPLEX + double _Complex C; +#endif } value; PyObject *obj; Py_ssize_t size; /* for the 'V' tag */ From 6eba44588351d7345ab38e2c73cdbd1bf605fc65 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 25 Jun 2024 15:39:02 +0300 Subject: [PATCH 41/55] cleanup: use "complex" instead of _Complex --- Modules/_ctypes/_ctypes_test.c | 2 +- Modules/_ctypes/callproc.c | 6 +++++- Modules/_ctypes/ctypes.h | 6 +++++- configure | 4 ++-- configure.ac | 4 ++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index ac608062c85a65..3e3a7b6e5d96f4 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -15,7 +15,7 @@ #ifdef HAVE_C_COMPLEX # include "../_complex.h" // csqrt() -# undef I +# undef I // for _ctypes_test_generated.c.h #endif #include // printf() #include // qsort() diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 27b4dd4b9ce359..e1d16f6900a47c 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -105,6 +105,10 @@ module _ctypes #include "pycore_global_objects.h"// _Py_ID() #include "pycore_traceback.h" // _PyTraceback_Add() +#ifdef HAVE_C_COMPLEX +#include "../complex.h" // complex +#endif + #include "clinic/callproc.c.h" #define CTYPES_CAPSULE_NAME_PYMEM "_ctypes pymem" @@ -652,7 +656,7 @@ union result { float f; void *p; #ifdef HAVE_C_COMPLEX - double _Complex C; + double complex C; #endif }; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index e004e128db8db1..96c238c45b6277 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -5,6 +5,10 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() +#ifdef HAVE_C_COMPLEX +# include "../complex.h" // complex +#endif + #ifndef MS_WIN32 #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) @@ -394,7 +398,7 @@ struct tagPyCArgObject { float f; void *p; #ifdef HAVE_C_COMPLEX - double _Complex C; + double complex C; #endif } value; PyObject *obj; diff --git a/configure b/configure index dc8a176e02669a..d750e33569455d 100755 --- a/configure +++ b/configure @@ -13862,8 +13862,8 @@ else $as_nop #include int main(void) { - double _Complex z = 1 + _Complex_I*2; - z = z + _Complex_I*z; + double complex z = 1 + 2*I; + z = z + z*I; return (creal(z) != -1) || (cimag(z) != 3); } _ACEOF diff --git a/configure.ac b/configure.ac index 1bb29a32d88223..cafe05afe3d27a 100644 --- a/configure.ac +++ b/configure.ac @@ -3774,8 +3774,8 @@ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main(void) { - double _Complex z = 1 + _Complex_I*2; - z = z + _Complex_I*z; + double complex z = 1 + 2*I; + z = z + z*I; return (creal(z) != -1) || (cimag(z) != 3); }]])], [ac_cv_c_complex_supported=yes], [ac_cv_c_complex_supported=no], From a6ac463441d0347895c4a6660c348baf20823a58 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 26 Jun 2024 04:34:55 +0300 Subject: [PATCH 42/55] address review: * move declaration * remove import * expand configure test --- Lib/test/test_ctypes/test_numbers.py | 6 +----- Modules/_ctypes/cfield.c | 2 +- configure | 13 ++++++++++--- configure.ac | 13 ++++++++++--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index 47a9f5d37bf73c..ed486f40aa8f8d 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -8,10 +8,6 @@ c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, c_longdouble, c_bool) -try: - from ctypes import c_double_complex -except ImportError: - pass def valid_ranges(*types): @@ -117,7 +113,7 @@ def test_floats(self): @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") def test_complex(self): - for t in [c_double_complex]: + for t in [ctypes.c_double_complex]: self.assertEqual(t(1).value, 1+0j) self.assertEqual(t(1.0).value, 1+0j) self.assertEqual(t(1+0.125j).value, 1+0.125j) diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 5a0a0948731652..3f33272e853e34 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -1096,11 +1096,11 @@ static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { Py_complex c = PyComplex_AsCComplex(value); - double complex x = CMPLX(c.real, c.imag); if (c.real == -1 && PyErr_Occurred()) { return NULL; } + double complex x = CMPLX(c.real, c.imag); memcpy(ptr, &x, sizeof(x)); _RET(value); } diff --git a/configure b/configure index d750e33569455d..574b6cb08e1e44 100755 --- a/configure +++ b/configure @@ -13860,11 +13860,18 @@ else $as_nop /* end confdefs.h. */ #include +#define test(type, out) \ +{ \ + type complex z = 1 + 2*I; z = z*z; \ + (out) = (out) || creal(z) != -3 || cimag(z) != 4; \ +} int main(void) { - double complex z = 1 + 2*I; - z = z + z*I; - return (creal(z) != -1) || (cimag(z) != 3); + int res = 0; + test(float, res); + test(double, res); + test(long double, res); + return res; } _ACEOF if ac_fn_c_try_run "$LINENO" diff --git a/configure.ac b/configure.ac index cafe05afe3d27a..bd4ec426f8a3c6 100644 --- a/configure.ac +++ b/configure.ac @@ -3772,11 +3772,18 @@ esac # of __STDC_IEC_559_COMPLEX__. AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include +#define test(type, out) \ +{ \ + type complex z = 1 + 2*I; z = z*z; \ + (out) = (out) || creal(z) != -3 || cimag(z) != 4; \ +} int main(void) { - double complex z = 1 + 2*I; - z = z + z*I; - return (creal(z) != -1) || (cimag(z) != 3); + int res = 0; + test(float, res); + test(double, res); + test(long double, res); + return res; }]])], [ac_cv_c_complex_supported=yes], [ac_cv_c_complex_supported=no], [ac_cv_c_complex_supported=no]) From 615e8dee6ba5eb63f35f22a446fa89762470b430 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 26 Jun 2024 04:48:06 +0300 Subject: [PATCH 43/55] Update Modules/_ctypes/_ctypes.c Co-authored-by: Victor Stinner --- Modules/_ctypes/_ctypes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 3526e5f9d3ff72..f5c679aa3dac9e 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2237,9 +2237,9 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) stginfo->ffi_type_pointer.size = fmt->pffi_type->size; stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment; stginfo->ffi_type_pointer.type = fmt->pffi_type->type; - stginfo->ffi_type_pointer.elements = PyMem_Malloc(2*sizeof(ffi_type)); + stginfo->ffi_type_pointer.elements = PyMem_Malloc(2 * sizeof(ffi_type)); memcpy(stginfo->ffi_type_pointer.elements, - fmt->pffi_type->elements, 2*sizeof(ffi_type)); + fmt->pffi_type->elements, 2 * sizeof(ffi_type)); } stginfo->align = fmt->pffi_type->alignment; stginfo->length = 0; From f7d9973dc81ebd93067ecb028c5757385433bfcf Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 26 Jun 2024 10:56:57 +0300 Subject: [PATCH 44/55] address review: renamed macro (->PY_HAVE_C_COMPLEX) --- Modules/_complex.h | 4 ++-- Modules/_ctypes/_ctypes.c | 2 +- Modules/_ctypes/_ctypes_test.c | 4 ++-- Modules/_ctypes/callproc.c | 4 ++-- Modules/_ctypes/cfield.c | 8 ++++---- Modules/_ctypes/ctypes.h | 4 ++-- configure | 2 +- configure.ac | 2 +- pyconfig.h.in | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Modules/_complex.h b/Modules/_complex.h index 4e66a4152e4056..702d57abe6fec6 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -1,7 +1,7 @@ /* Workarounds for buggy complex number arithmetic implementations. */ -#ifndef HAVE_C_COMPLEX -# error "this header file should only be included if HAVE_C_COMPLEX is defined" +#ifndef PY_HAVE_C_COMPLEX +# error "this header file should only be included if PY_HAVE_C_COMPLEX is defined" #endif #include diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index f5c679aa3dac9e..29112d6c4785f5 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1750,7 +1750,7 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g"; #else static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 3e3a7b6e5d96f4..eafd0e31c8d34d 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,7 +13,7 @@ #include -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX # include "../_complex.h" // csqrt() # undef I // for _ctypes_test_generated.c.h #endif @@ -447,7 +447,7 @@ EXPORT(double) my_sqrt(double a) return sqrt(a); } -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index e1d16f6900a47c..fb20a459185b18 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -105,7 +105,7 @@ module _ctypes #include "pycore_global_objects.h"// _Py_ID() #include "pycore_traceback.h" // _PyTraceback_Add() -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX #include "../complex.h" // complex #endif @@ -655,7 +655,7 @@ union result { double d; float f; void *p; -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX double complex C; #endif }; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 3f33272e853e34..4f14e02414351f 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -11,7 +11,7 @@ #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_call.h" // _PyObject_CallNoArgs() -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX # include "../_complex.h" // complex #endif @@ -1091,7 +1091,7 @@ d_get(void *ptr, Py_ssize_t size) return PyFloat_FromDouble(val); } -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { @@ -1620,7 +1620,7 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX { 'C', C_set, C_get, NULL}, #endif { 'g', g_set, g_get, NULL}, @@ -1673,7 +1673,7 @@ _ctypes_init_fielddesc(void) case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'c': fd->pffi_type = &ffi_type_schar; break; case 'd': fd->pffi_type = &ffi_type_double; break; -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX case 'C': fd->pffi_type = &ffi_type_complex_double; break; #endif case 'g': fd->pffi_type = &ffi_type_longdouble; break; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 96c238c45b6277..c54d00518d2ff0 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -5,7 +5,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX # include "../complex.h" // complex #endif @@ -397,7 +397,7 @@ struct tagPyCArgObject { double d; float f; void *p; -#ifdef HAVE_C_COMPLEX +#ifdef PY_HAVE_C_COMPLEX double complex C; #endif } value; diff --git a/configure b/configure index 574b6cb08e1e44..a29b907b203cf9 100755 --- a/configure +++ b/configure @@ -13886,7 +13886,7 @@ fi if test "$ac_cv_c_complex_supported" = "yes"; then -printf "%s\n" "#define HAVE_C_COMPLEX 1" >>confdefs.h +printf "%s\n" "#define PY_HAVE_C_COMPLEX 1" >>confdefs.h fi diff --git a/configure.ac b/configure.ac index bd4ec426f8a3c6..93ff4208a70749 100644 --- a/configure.ac +++ b/configure.ac @@ -3788,7 +3788,7 @@ int main(void) [ac_cv_c_complex_supported=no], [ac_cv_c_complex_supported=no]) if test "$ac_cv_c_complex_supported" = "yes"; then - AC_DEFINE([HAVE_C_COMPLEX], [1], + AC_DEFINE([PY_HAVE_C_COMPLEX], [1], [Defined if _Complex C type is available.]) fi diff --git a/pyconfig.h.in b/pyconfig.h.in index e5d0c7a7b92b8b..bb8a1fe2e31b5f 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -224,7 +224,7 @@ #undef HAVE_CURSES_WCHGAT /* Defined if _Complex C type is available. */ -#undef HAVE_C_COMPLEX +#undef PY_HAVE_C_COMPLEX /* Define to 1 if you have the header file. */ #undef HAVE_DB_H From 3d170bd9c9531aa83d5434ffeae424b5de6edd53 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 26 Jun 2024 11:28:15 +0300 Subject: [PATCH 45/55] + autoreconf --- pyconfig.h.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyconfig.h.in b/pyconfig.h.in index bb8a1fe2e31b5f..b1c539cee7a2e1 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -223,9 +223,6 @@ /* Define if you have the 'wchgat' function. */ #undef HAVE_CURSES_WCHGAT -/* Defined if _Complex C type is available. */ -#undef PY_HAVE_C_COMPLEX - /* Define to 1 if you have the header file. */ #undef HAVE_DB_H @@ -1630,6 +1627,9 @@ /* Define if you want to coerce the C locale to a UTF-8 based locale */ #undef PY_COERCE_C_LOCALE +/* Defined if _Complex C type is available. */ +#undef PY_HAVE_C_COMPLEX + /* Define to 1 if you have the perf trampoline. */ #undef PY_HAVE_PERF_TRAMPOLINE From 4dd044cd6d4385e3d3c4f75a716f37657fd130b1 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 26 Jun 2024 11:34:00 +0300 Subject: [PATCH 46/55] + test to ensure CMPLX preserves special components --- Lib/test/test_ctypes/test_numbers.py | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index ed486f40aa8f8d..b3816f61a6e7aa 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -3,6 +3,8 @@ import struct import sys import unittest +from itertools import combinations +from math import copysign, isnan from operator import truth from ctypes import (byref, sizeof, alignment, c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, @@ -56,7 +58,38 @@ def __complex__(self): return 1+1j +INF = float("inf") +NAN = float("nan") + + class NumberTestCase(unittest.TestCase): + # from Lib/test/test_complex.py + def assertFloatsAreIdentical(self, x, y): + """assert that floats x and y are identical, in the sense that: + (1) both x and y are nans, or + (2) both x and y are infinities, with the same sign, or + (3) both x and y are zeros, with the same sign, or + (4) x and y are both finite and nonzero, and x == y + + """ + msg = 'floats {!r} and {!r} are not identical' + + if isnan(x) or isnan(y): + if isnan(x) and isnan(y): + return + elif x == y: + if x != 0.0: + return + # both zero; check that signs match + elif copysign(1.0, x) == copysign(1.0, y): + return + else: + msg += ': zeros have different signs' + self.fail(msg.format(x, y)) + + def assertComplexesAreIdentical(self, x, y): + self.assertFloatsAreIdentical(x.real, y.real) + self.assertFloatsAreIdentical(x.imag, y.imag) def test_default_init(self): # default values are set to zero @@ -121,6 +154,18 @@ def test_complex(self): self.assertEqual(t(FloatLike()).value, 2+0j) self.assertEqual(t(ComplexLike()).value, 1+1j) + @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), + "requires C11 complex type") + def test_complex_round_trip(self): + # Ensure complexes transformed exactly. The CMPLX macro should + # preserve special components (like inf/nan or signed zero). + values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2, + -3, INF, -INF, NAN], 2)] + for z in values: + with self.subTest(z=z): + z2 = ctypes.c_double_complex(z).value + self.assertComplexesAreIdentical(z, z2) + def test_integers(self): f = FloatLike() d = IntLike() From 4cf7045860bc277de0217e558a000f72a50b64c1 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 28 Jun 2024 03:46:59 +0300 Subject: [PATCH 47/55] address review: rename macros to Py_HAVE_C_COMPLEX --- Modules/_complex.h | 4 ++-- Modules/_ctypes/_ctypes.c | 2 +- Modules/_ctypes/_ctypes_test.c | 4 ++-- Modules/_ctypes/callproc.c | 4 ++-- Modules/_ctypes/cfield.c | 8 ++++---- Modules/_ctypes/ctypes.h | 4 ++-- configure | 2 +- configure.ac | 2 +- pyconfig.h.in | 6 +++--- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Modules/_complex.h b/Modules/_complex.h index 702d57abe6fec6..1c1d1c8cae51b9 100644 --- a/Modules/_complex.h +++ b/Modules/_complex.h @@ -1,7 +1,7 @@ /* 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" +#ifndef Py_HAVE_C_COMPLEX +# error "this header file should only be included if Py_HAVE_C_COMPLEX is defined" #endif #include diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 29112d6c4785f5..17955fd4b77686 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1750,7 +1750,7 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g"; #else static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index eafd0e31c8d34d..5bc108154a08f5 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,7 +13,7 @@ #include -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX # include "../_complex.h" // csqrt() # undef I // for _ctypes_test_generated.c.h #endif @@ -447,7 +447,7 @@ EXPORT(double) my_sqrt(double a) return sqrt(a); } -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index fb20a459185b18..c2b80c6c787530 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -105,7 +105,7 @@ module _ctypes #include "pycore_global_objects.h"// _Py_ID() #include "pycore_traceback.h" // _PyTraceback_Add() -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX #include "../complex.h" // complex #endif @@ -655,7 +655,7 @@ union result { double d; float f; void *p; -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX double complex C; #endif }; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 4f14e02414351f..f023e52248d8e4 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -11,7 +11,7 @@ #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_call.h" // _PyObject_CallNoArgs() -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX # include "../_complex.h" // complex #endif @@ -1091,7 +1091,7 @@ d_get(void *ptr, Py_ssize_t size) return PyFloat_FromDouble(val); } -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { @@ -1620,7 +1620,7 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX { 'C', C_set, C_get, NULL}, #endif { 'g', g_set, g_get, NULL}, @@ -1673,7 +1673,7 @@ _ctypes_init_fielddesc(void) case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'c': fd->pffi_type = &ffi_type_schar; break; case 'd': fd->pffi_type = &ffi_type_double; break; -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX case 'C': fd->pffi_type = &ffi_type_complex_double; break; #endif case 'g': fd->pffi_type = &ffi_type_longdouble; break; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index c54d00518d2ff0..041710b8988077 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -5,7 +5,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX # include "../complex.h" // complex #endif @@ -397,7 +397,7 @@ struct tagPyCArgObject { double d; float f; void *p; -#ifdef PY_HAVE_C_COMPLEX +#ifdef Py_HAVE_C_COMPLEX double complex C; #endif } value; diff --git a/configure b/configure index a29b907b203cf9..9648804b85c5a7 100755 --- a/configure +++ b/configure @@ -13886,7 +13886,7 @@ fi if test "$ac_cv_c_complex_supported" = "yes"; then -printf "%s\n" "#define PY_HAVE_C_COMPLEX 1" >>confdefs.h +printf "%s\n" "#define Py_HAVE_C_COMPLEX 1" >>confdefs.h fi diff --git a/configure.ac b/configure.ac index 93ff4208a70749..7e11c6d186d191 100644 --- a/configure.ac +++ b/configure.ac @@ -3788,7 +3788,7 @@ int main(void) [ac_cv_c_complex_supported=no], [ac_cv_c_complex_supported=no]) if test "$ac_cv_c_complex_supported" = "yes"; then - AC_DEFINE([PY_HAVE_C_COMPLEX], [1], + AC_DEFINE([Py_HAVE_C_COMPLEX], [1], [Defined if _Complex C type is available.]) fi diff --git a/pyconfig.h.in b/pyconfig.h.in index b1c539cee7a2e1..bb8b765d2c5774 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1627,9 +1627,6 @@ /* Define if you want to coerce the C locale to a UTF-8 based locale */ #undef PY_COERCE_C_LOCALE -/* Defined if _Complex C type is available. */ -#undef PY_HAVE_C_COMPLEX - /* Define to 1 if you have the perf trampoline. */ #undef PY_HAVE_PERF_TRAMPOLINE @@ -1662,6 +1659,9 @@ SipHash13: 3, externally defined: 0 */ #undef Py_HASH_ALGORITHM +/* Defined if _Complex C type is available. */ +#undef Py_HAVE_C_COMPLEX + /* Define if rl_startup_hook takes arguments */ #undef Py_RL_STARTUP_HOOK_TAKES_ARGS From 264fa7dc9b9c93911b1aa27dc0c4863121d1befe Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 28 Jun 2024 13:59:09 +0300 Subject: [PATCH 48/55] fix typos and adjust Makefile.pre.in --- Makefile.pre.in | 2 +- Modules/_ctypes/callproc.c | 2 +- Modules/_ctypes/ctypes.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 6551c2ec4cea87..845f7e8fd51710 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -3111,7 +3111,7 @@ 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__BLAKE2_DEPS=$(srcdir)/Modules/_blake2/impl/blake2-config.h $(srcdir)/Modules/_blake2/impl/blake2-impl.h $(srcdir)/Modules/_blake2/impl/blake2.h $(srcdir)/Modules/_blake2/impl/blake2b-load-sse2.h $(srcdir)/Modules/_blake2/impl/blake2b-load-sse41.h $(srcdir)/Modules/_blake2/impl/blake2b-ref.c $(srcdir)/Modules/_blake2/impl/blake2b-round.h $(srcdir)/Modules/_blake2/impl/blake2b.c $(srcdir)/Modules/_blake2/impl/blake2s-load-sse2.h $(srcdir)/Modules/_blake2/impl/blake2s-load-sse41.h $(srcdir)/Modules/_blake2/impl/blake2s-load-xop.h $(srcdir)/Modules/_blake2/impl/blake2s-ref.c $(srcdir)/Modules/_blake2/impl/blake2s-round.h $(srcdir)/Modules/_blake2/impl/blake2s.c $(srcdir)/Modules/_blake2/blake2module.h $(srcdir)/Modules/hashlib.h -MODULE__CTYPES_DEPS=$(srcdir)/Modules/_ctypes/ctypes.h +MODULE__CTYPES_DEPS=$(srcdir)/Modules/_ctypes/ctypes.h $(srcdir)/Modules/_complex.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/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index c2b80c6c787530..27d7b8001386ef 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -106,7 +106,7 @@ module _ctypes #include "pycore_traceback.h" // _PyTraceback_Add() #ifdef Py_HAVE_C_COMPLEX -#include "../complex.h" // complex +#include "../_complex.h" // complex #endif #include "clinic/callproc.c.h" diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 041710b8988077..fa3dd1515fe211 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -6,7 +6,7 @@ #include "pycore_typeobject.h" // _PyType_GetModuleState() #ifdef Py_HAVE_C_COMPLEX -# include "../complex.h" // complex +# include "../_complex.h" // complex #endif #ifndef MS_WIN32 From f54b96486ac2626f11d33eb4cc5da35721a244c9 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 29 Jun 2024 04:26:39 +0300 Subject: [PATCH 49/55] enable Py_HAVE_C_COMPLEX only if libff support complex numbers --- configure | 5 ++++- configure.ac | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 9648804b85c5a7..b21582f267848b 100755 --- a/configure +++ b/configure @@ -13845,7 +13845,7 @@ printf "%s\n" "$AIX_BUILDDATE" >&6; } *) ;; esac -# check for _Complex C type +# check for _Complex C type and it's support by libffi # # Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost # none properly support C11+ Annex G (where pure imaginary types @@ -13860,6 +13860,9 @@ else $as_nop /* end confdefs.h. */ #include +#ifndef FFI_TYPE_COMPLEX +#error "libffi version has no support for _Complex type" +#endif #define test(type, out) \ { \ type complex z = 1 + 2*I; z = z*z; \ diff --git a/configure.ac b/configure.ac index 7e11c6d186d191..5df845a402567a 100644 --- a/configure.ac +++ b/configure.ac @@ -3763,7 +3763,7 @@ dnl The AIX_BUILDDATE is obtained from the kernel fileset - bos.mp64 *) ;; esac -# check for _Complex C type +# check for _Complex C type and it's support by libffi # # Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost # none properly support C11+ Annex G (where pure imaginary types @@ -3772,6 +3772,9 @@ esac # of __STDC_IEC_559_COMPLEX__. AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include +#ifndef FFI_TYPE_COMPLEX +#error "libffi version has no support for _Complex type" +#endif #define test(type, out) \ { \ type complex z = 1 + 2*I; z = z*z; \ From 23db200d14fc576a8154ec677ec66ba21f13d9aa Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 29 Jun 2024 05:43:32 +0300 Subject: [PATCH 50/55] Revert "enable Py_HAVE_C_COMPLEX only if libff support complex numbers" This reverts commit f54b96486ac2626f11d33eb4cc5da35721a244c9. --- configure | 5 +---- configure.ac | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/configure b/configure index b21582f267848b..9648804b85c5a7 100755 --- a/configure +++ b/configure @@ -13845,7 +13845,7 @@ printf "%s\n" "$AIX_BUILDDATE" >&6; } *) ;; esac -# check for _Complex C type and it's support by libffi +# check for _Complex C type # # Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost # none properly support C11+ Annex G (where pure imaginary types @@ -13860,9 +13860,6 @@ else $as_nop /* end confdefs.h. */ #include -#ifndef FFI_TYPE_COMPLEX -#error "libffi version has no support for _Complex type" -#endif #define test(type, out) \ { \ type complex z = 1 + 2*I; z = z*z; \ diff --git a/configure.ac b/configure.ac index 5df845a402567a..7e11c6d186d191 100644 --- a/configure.ac +++ b/configure.ac @@ -3763,7 +3763,7 @@ dnl The AIX_BUILDDATE is obtained from the kernel fileset - bos.mp64 *) ;; esac -# check for _Complex C type and it's support by libffi +# check for _Complex C type # # Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost # none properly support C11+ Annex G (where pure imaginary types @@ -3772,9 +3772,6 @@ esac # of __STDC_IEC_559_COMPLEX__. AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -#ifndef FFI_TYPE_COMPLEX -#error "libffi version has no support for _Complex type" -#endif #define test(type, out) \ { \ type complex z = 1 + 2*I; z = z*z; \ From 5a7e3663e895e745c52f77a63e7dede00f034262 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 29 Jun 2024 05:51:07 +0300 Subject: [PATCH 51/55] ifdef Py_HAVE_C_COMPLEX -> if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) --- Modules/_ctypes/_ctypes.c | 2 +- Modules/_ctypes/_ctypes_test.c | 4 ++-- Modules/_ctypes/callproc.c | 4 ++-- Modules/_ctypes/cfield.c | 8 ++++---- Modules/_ctypes/ctypes.h | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 17955fd4b77686..29da4d21989809 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1750,7 +1750,7 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g"; #else static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 5bc108154a08f5..632933926edd52 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,7 +13,7 @@ #include -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) # include "../_complex.h" // csqrt() # undef I // for _ctypes_test_generated.c.h #endif @@ -447,7 +447,7 @@ EXPORT(double) my_sqrt(double a) return sqrt(a); } -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 27d7b8001386ef..53754071c97e94 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -105,7 +105,7 @@ module _ctypes #include "pycore_global_objects.h"// _Py_ID() #include "pycore_traceback.h" // _PyTraceback_Add() -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) #include "../_complex.h" // complex #endif @@ -655,7 +655,7 @@ union result { double d; float f; void *p; -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) double complex C; #endif }; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index f023e52248d8e4..4de84d81bd46d5 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -11,7 +11,7 @@ #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_call.h" // _PyObject_CallNoArgs() -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) # include "../_complex.h" // complex #endif @@ -1091,7 +1091,7 @@ d_get(void *ptr, Py_ssize_t size) return PyFloat_FromDouble(val); } -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { @@ -1620,7 +1620,7 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) { 'C', C_set, C_get, NULL}, #endif { 'g', g_set, g_get, NULL}, @@ -1673,7 +1673,7 @@ _ctypes_init_fielddesc(void) case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'c': fd->pffi_type = &ffi_type_schar; break; case 'd': fd->pffi_type = &ffi_type_double; break; -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) case 'C': fd->pffi_type = &ffi_type_complex_double; break; #endif case 'g': fd->pffi_type = &ffi_type_longdouble; break; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index fa3dd1515fe211..3705d6bc79eea9 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -5,7 +5,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) # include "../_complex.h" // complex #endif @@ -397,7 +397,7 @@ struct tagPyCArgObject { double d; float f; void *p; -#ifdef Py_HAVE_C_COMPLEX +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) double complex C; #endif } value; From 388e2ca6cc501ac557fd55ededc29a75a744fc4d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 29 Jun 2024 08:57:41 +0300 Subject: [PATCH 52/55] + missing ffi.h imports --- Modules/_ctypes/_ctypes_test.c | 2 ++ Modules/_ctypes/cfield.c | 7 +++---- Modules/_ctypes/ctypes.h | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 632933926edd52..89c0b27e821caa 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,6 +13,8 @@ #include +#include // FFI_TYPE_COMPLEX + #if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) # include "../_complex.h" // csqrt() # undef I // for _ctypes_test_generated.c.h diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 4de84d81bd46d5..94972ca03b878f 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -11,13 +11,12 @@ #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_call.h" // _PyObject_CallNoArgs() -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) -# include "../_complex.h" // complex -#endif - #include #include "ctypes.h" +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +# include "../_complex.h" // complex +#endif #define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem" diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 3705d6bc79eea9..9ab417df77f843 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -2,6 +2,8 @@ # include #endif +#include // FFI_TYPE_COMPLEX + #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() From e8885653b9b8b452538a47725407baf5d603d6c6 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 29 Jun 2024 10:16:11 +0300 Subject: [PATCH 53/55] + add libffi's cflags/ldflags to _ctypes_test.c deps --- PCbuild/_ctypes_test.vcxproj | 1 + configure | 4 ++-- configure.ac | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/PCbuild/_ctypes_test.vcxproj b/PCbuild/_ctypes_test.vcxproj index 50d8575ad7bda3..f15b80852e362a 100644 --- a/PCbuild/_ctypes_test.vcxproj +++ b/PCbuild/_ctypes_test.vcxproj @@ -87,6 +87,7 @@ + diff --git a/configure b/configure index 9648804b85c5a7..e7c5f888a9637d 100755 --- a/configure +++ b/configure @@ -31494,8 +31494,8 @@ fi if test "x$py_cv_module__ctypes_test" = xyes then : - - as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_LDFLAGS=$LIBM$as_nl" + as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_CFLAGS=$LIBFFI_CFLAGS$as_nl" + as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_LDFLAGS=$LIBFFI_LIBS $LIBM$as_nl" fi if test "$py_cv_module__ctypes_test" = yes; then diff --git a/configure.ac b/configure.ac index 7e11c6d186d191..976dc7fe1c2dce 100644 --- a/configure.ac +++ b/configure.ac @@ -7790,7 +7790,7 @@ PY_STDLIB_MOD([xxsubtype], [test "$TEST_MODULES" = yes]) PY_STDLIB_MOD([_xxtestfuzz], [test "$TEST_MODULES" = yes]) PY_STDLIB_MOD([_ctypes_test], [test "$TEST_MODULES" = yes], [test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes], - [], [$LIBM]) + [$LIBFFI_CFLAGS], [$LIBFFI_LIBS $LIBM]) dnl Limited API template modules. dnl Emscripten does not support shared libraries yet. From e9cab4a567817c553c563a48a1e60a2dd43dc287 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 29 Jun 2024 14:07:55 +0300 Subject: [PATCH 54/55] Adjust test in _ctypes.c to not use FFI_TYPE_COMPLEX define --- Modules/_ctypes/_ctypes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 6398d35cfaeb49..f1050a08644f71 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2230,7 +2230,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) goto error; } - if (fmt->pffi_type->type != FFI_TYPE_COMPLEX) { + if (!fmt->pffi_type->elements) { stginfo->ffi_type_pointer = *fmt->pffi_type; } else { From 6d5bf66d4ae36f27826c630fb1ac6a5bbe0eaee0 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 30 Jun 2024 14:35:34 +0300 Subject: [PATCH 55/55] sed: FFI_TYPE_COMPLEX -> FFI_TARGET_HAS_COMPLEX_TYPE --- Modules/_ctypes/_ctypes.c | 2 +- Modules/_ctypes/_ctypes_test.c | 6 +++--- Modules/_ctypes/callproc.c | 4 ++-- Modules/_ctypes/cfield.c | 8 ++++---- Modules/_ctypes/ctypes.h | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index f1050a08644f71..3647361b13a52c 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1750,7 +1750,7 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g"; #else static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 89c0b27e821caa..cbc8f8b0b453af 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -13,9 +13,9 @@ #include -#include // FFI_TYPE_COMPLEX +#include // FFI_TARGET_HAS_COMPLEX_TYPE -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) # include "../_complex.h" // csqrt() # undef I // for _ctypes_test_generated.c.h #endif @@ -449,7 +449,7 @@ EXPORT(double) my_sqrt(double a) return sqrt(a); } -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) EXPORT(double complex) my_csqrt(double complex a) { return csqrt(a); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 53754071c97e94..a83fa19af32402 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -105,7 +105,7 @@ module _ctypes #include "pycore_global_objects.h"// _Py_ID() #include "pycore_traceback.h" // _PyTraceback_Add() -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) #include "../_complex.h" // complex #endif @@ -655,7 +655,7 @@ union result { double d; float f; void *p; -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) double complex C; #endif }; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 94972ca03b878f..40b72d83d16aeb 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -14,7 +14,7 @@ #include #include "ctypes.h" -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) # include "../_complex.h" // complex #endif @@ -1090,7 +1090,7 @@ d_get(void *ptr, Py_ssize_t size) return PyFloat_FromDouble(val); } -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) static PyObject * C_set(void *ptr, PyObject *value, Py_ssize_t size) { @@ -1619,7 +1619,7 @@ static struct fielddesc formattable[] = { { 'B', B_set, B_get, NULL}, { 'c', c_set, c_get, NULL}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) { 'C', C_set, C_get, NULL}, #endif { 'g', g_set, g_get, NULL}, @@ -1672,7 +1672,7 @@ _ctypes_init_fielddesc(void) case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'c': fd->pffi_type = &ffi_type_schar; break; case 'd': fd->pffi_type = &ffi_type_double; break; -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) case 'C': fd->pffi_type = &ffi_type_complex_double; break; #endif case 'g': fd->pffi_type = &ffi_type_longdouble; break; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 9ab417df77f843..5ba5eb3851a690 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -2,12 +2,12 @@ # include #endif -#include // FFI_TYPE_COMPLEX +#include // FFI_TARGET_HAS_COMPLEX_TYPE #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) # include "../_complex.h" // complex #endif @@ -399,7 +399,7 @@ struct tagPyCArgObject { double d; float f; void *p; -#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TYPE_COMPLEX) +#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) double complex C; #endif } value;