Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r2965:c0c2020872d3 Date: 2017-06-02 10:02 +0200 http://bitbucket.org/cffi/cffi/changeset/c0c2020872d3/
Log: Fix: the type char32_t is defined by the standard as always unsigned diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -143,6 +143,7 @@ #define CT_IS_UNSIZED_CHAR_A 0x00800000 #define CT_LAZY_FIELD_LIST 0x01000000 #define CT_WITH_PACKED_CHANGE 0x02000000 +#define CT_IS_SIGNED_WCHAR 0x04000000 #define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ CT_PRIMITIVE_UNSIGNED | \ CT_PRIMITIVE_CHAR | \ @@ -1591,8 +1592,8 @@ return 0; } case 4: { - int res = _convert_to_char32_t(init); - if (res == -1 && PyErr_Occurred()) + cffi_char32_t res = _convert_to_char32_t(init); + if (res == (cffi_char32_t)-1 && PyErr_Occurred()) return -1; *(cffi_char32_t *)data = res; return 0; @@ -2084,9 +2085,12 @@ case 2: return PyInt_FromLong((long)*(cffi_char16_t *)cd->c_data); case 4: - /* NB. cast via int32_t instead of cffi_char32_t, so that - we expose a signed result to the user */ - return PyInt_FromLong((long)*(int32_t *)cd->c_data); + if (cd->c_type->ct_flags & CT_IS_SIGNED_WCHAR) + return PyInt_FromLong((long)*(int32_t *)cd->c_data); + else if (sizeof(long) > 4) + return PyInt_FromLong(*(uint32_t *)cd->c_data); + else + return PyLong_FromUnsignedLong(*(uint32_t *)cd->c_data); } } else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { @@ -3687,8 +3691,15 @@ "cannot cast %s to ctype '%s'", err_buf, ct->ct_name); return NULL; } - /* the user sees char32_t being signed, but not char16_t */ - value = (int32_t)ordinal; + /* the types char16_t and char32_t are both unsigned. However, + wchar_t might be signed. In theory it does not matter, + because 'ordinal' comes from a regular Python unicode. */ +#ifdef HAVE_WCHAR_H + if (ct->ct_flags & CT_IS_SIGNED_WCHAR) + value = (wchar_t)ordinal; + else +#endif + value = ordinal; } else if (PyBytes_Check(ob)) { int res = _convert_to_char(ob); @@ -3733,7 +3744,10 @@ Py_DECREF(io); return -1; } - *out_value = (int32_t)ordinal; + /* the signness of the 32-bit version of wide chars should not + * matter here, because 'ordinal' comes from a normal Python + * unicode string */ + *out_value = ordinal; return 1; } return 0; @@ -4195,7 +4209,8 @@ #ifdef HAVE_WCHAR_H # define ENUM_PRIMITIVE_TYPES_WCHAR \ - EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR ) + EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR | \ + (((wchar_t)-1) > 0 ? 0 : CT_IS_SIGNED_WCHAR)) #else # define ENUM_PRIMITIVE_TYPES_WCHAR /* nothing */ #endif diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -2101,12 +2101,16 @@ _test_wchar_variant("wchar_t") def test_char16(): - assert sizeof(new_primitive_type("char16_t")) == 2 + BChar16 = new_primitive_type("char16_t") + assert sizeof(BChar16) == 2 _test_wchar_variant("char16_t") + assert int(cast(BChar16, -1)) == 0xffff # always unsigned def test_char32(): - assert sizeof(new_primitive_type("char32_t")) == 4 + BChar32 = new_primitive_type("char32_t") + assert sizeof(BChar32) == 4 _test_wchar_variant("char32_t") + assert int(cast(BChar32, -1)) == 0xffffffff # always unsigned def _test_wchar_variant(typename): BWChar = new_primitive_type(typename) diff --git a/c/wchar_helper.h b/c/wchar_helper.h --- a/c/wchar_helper.h +++ b/c/wchar_helper.h @@ -4,7 +4,6 @@ typedef uint16_t cffi_char16_t; typedef uint32_t cffi_char32_t; -/* NB. cffi_char32_t is unsigned to make the logic here a bit easier */ #if Py_UNICODE_SIZE == 2 diff --git a/cffi/_cffi_include.h b/cffi/_cffi_include.h --- a/cffi/_cffi_include.h +++ b/cffi/_cffi_include.h @@ -64,7 +64,7 @@ # endif # if _MSC_VER < 1900 || !defined(__cplusplus) /* MSVC < 2015, or plain C */ typedef uint16_t char16_t; - typedef int32_t char32_t; + typedef uint32_t char32_t; # endif #else # include <stdint.h> _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit