[pypy-commit] cffi default: Fix: the type char32_t is defined by the standard as always unsigned
arigo
pypy.commits at gmail.com
Fri Jun 2 04:02:47 EDT 2017
Author: Armin Rigo <arigo at 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>
More information about the pypy-commit
mailing list