[pypy-commit] cffi default: Change the hack: instead of passing None for NULL pointers, we pass 0.
arigo
noreply at buildbot.pypy.org
Thu Feb 28 17:32:11 CET 2013
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1176:d37c1ddac94c
Date: 2013-02-28 17:31 +0100
http://bitbucket.org/cffi/cffi/changeset/d37c1ddac94c/
Log: Change the hack: instead of passing None for NULL pointers, we pass
0. This is more compatible with C. Also accept 0 at other places
that expect a pointer.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -1120,6 +1120,11 @@
CTypeDescrObject *ctinit;
if (!CData_Check(init)) {
+ if (PyIntOrLong_Check(init) && !PyObject_IsTrue(init)) {
+ /* convert 0 to NULL */
+ *(char **)data = NULL;
+ return 0;
+ }
expected = "cdata pointer";
goto cannot_convert;
}
@@ -1604,16 +1609,26 @@
char *v_cdata, *w_cdata;
assert(CData_Check(v));
- if (!CData_Check(w))
- goto Unimplemented;
-
v_cdata = ((CDataObject *)v)->c_data;
- w_cdata = ((CDataObject *)w)->c_data;
+
+ if (!CData_Check(w)) {
+ if (PyIntOrLong_Check(w) && !PyObject_IsTrue(w) &&
+ !(((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY)) {
+ /* comparing a non-primitive with 0 */
+ w_cdata = NULL;
+ goto compare;
+ }
+ pyres = Py_NotImplemented;
+ goto done;
+ }
+
if ((op != Py_EQ && op != Py_NE) &&
((((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY) ||
(((CDataObject *)w)->c_type->ct_flags & CT_PRIMITIVE_ANY)))
goto Error;
+ w_cdata = ((CDataObject *)w)->c_data;
+ compare:
switch (op) {
case Py_EQ: res = (v_cdata == w_cdata); break;
case Py_NE: res = (v_cdata != w_cdata); break;
@@ -1628,10 +1643,6 @@
Py_INCREF(pyres);
return pyres;
- Unimplemented:
- pyres = Py_NotImplemented;
- goto done;
-
Error:
PyErr_SetString(PyExc_TypeError,
"cannot do comparison on a primitive cdata");
@@ -2067,7 +2078,12 @@
ctitem = ctptr->ct_itemdescr;
/* XXX some code duplication, how to avoid it? */
- if (init == Py_None) {
+ if (PyIntOrLong_Check(init) && !PyObject_IsTrue(init)) {
+ /* Convert 0 to NULL. Note that passing 0 is not ambigous,
+ despite the potential confusion: as a 'T*' argument, 0 means
+ NULL, but as a 'T[]' argument it would mean "array of size 0"
+ --- except that we specifically refuse to interpret numbers
+ as the array size when passing arguments. */
*output_data = NULL;
return 0;
}
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -399,6 +399,19 @@
assert (x == ["hello"]) is False
assert (x != ["hello"]) is True
+def test_cmp_pointer_with_0():
+ p = new_pointer_type(new_primitive_type("int"))
+ x = cast(p, 0)
+ assert (x == 0) is True
+ assert (x != 0) is False
+ assert (0 == x) is True
+ assert (0 != x) is False
+ y = cast(p, 42)
+ assert (y == 0) is False
+ assert (y != 0) is True
+ assert (0 == y) is False
+ assert (0 != y) is True
+
def test_invalid_indexing():
p = new_primitive_type("int")
x = cast(p, 42)
@@ -777,6 +790,7 @@
assert s.a2 == 456
assert s.a3 == 0
assert s.p4 == cast(BVoidP, 0)
+ assert s.p4 == 0
#
s = newp(BStructPtr, {'a2': 41122, 'a3': -123})
assert s.a1 == 0
@@ -791,6 +805,9 @@
assert s.p4 == p
#
s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)])
+ assert s.p4 == 0
+ #
+ s = newp(BStructPtr, [12, 34, 56, 0])
assert s.p4 == cast(BVoidP, 0)
#
py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None])
@@ -1009,8 +1026,12 @@
f = cast(BFunc23, _testfunc(23))
res = f(b"foo")
assert res == 1000 * ord(b'f')
- res = f(None)
+ res = f(0) # NULL
assert res == -42
+ res = f(long(0)) # NULL
+ assert res == -42
+ py.test.raises(TypeError, f, None)
+ py.test.raises(TypeError, f, 0.0)
def test_call_function_23_bis():
# declaring the function as int(unsigned char*)
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -1304,13 +1304,14 @@
| | a compatible type (i.e.| |``+``, ``-``, |
| | same type or ``char*`` | |bool() |
| | or ``void*``, or as an | | |
-| | array instead) `(*)` | | |
+| | array instead) `(*)`; | | |
+| | or ``0`` `(******)` | | |
+---------------+------------------------+ | |
| ``void *``, | another <cdata> with | | |
| ``char *`` | any pointer or array | | |
-| | type | | |
+| | type; or ``0`` | | |
+---------------+------------------------+ +----------------+
-| pointers to | same as pointers `(*)` | | ``[]``, ``+``, |
+| pointers to | same as pointers | | ``[]``, ``+``, |
| structure or | | | ``-``, bool(), |
| union | | | and read/write |
| | | | struct fields |
@@ -1350,9 +1351,6 @@
you need to specify it in a list of length 1; for example, a ``struct
foo *`` argument might be passed as ``[[field1, field2...]]``.
-.. versionadded:: 0.6
- You can also pass None to ``item *`` arguments (meaning NULL).
-
As an optimization, the CPython version of CFFI assumes that a function
with a ``char *`` argument to which you pass a Python string will not
actually modify the array of characters passed in, and so passes directly
@@ -1391,6 +1389,11 @@
If you really want to get their value as a string, use
``ffi.string(ffi.cast("the_enum_type", x.field))``.
+.. versionadded:: 0.6
+ `(******)` ``0`` is interpreted like ``ffi.NULL`` in most places.
+ It is the way both gcc and MSVC work. (Of course non-null integers
+ are not transparently interpreted as pointers; only ``0`` is.)
+
Reference: verifier
-------------------
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -1552,7 +1552,7 @@
p = ffi.new("char[]", b'\x10\x20\x30')
assert lib.sum3chars(p) == b'\x60'
-def test_passing_None():
+def test_passing_0_for_NULL():
ffi = FFI()
ffi.cdef("int seeme1(char *); int seeme2(int *);")
lib = ffi.verify("""
@@ -1564,6 +1564,12 @@
}
""")
assert lib.seeme1(b"foo") == 0
- assert lib.seeme1(None) == 1
+ assert lib.seeme1(0) == 1
+ assert lib.seeme1(long(0)) == 1
assert lib.seeme2([42, 43]) == 0
- assert lib.seeme2(None) == 1
+ assert lib.seeme2(0) == 1
+ assert lib.seeme2(long(0)) == 1
+ py.test.raises(TypeError, lib.seeme1, None)
+ py.test.raises(TypeError, lib.seeme2, None)
+ py.test.raises(TypeError, lib.seeme1, 0.0)
+ py.test.raises(TypeError, lib.seeme2, 0.0)
More information about the pypy-commit
mailing list