[pypy-commit] cffi default: Arithmetic using "void *" should work; at least it does in gcc without

arigo noreply at buildbot.pypy.org
Sat Nov 9 09:09:58 CET 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r1395:88d2b9436efd
Date: 2013-11-09 09:09 +0100
http://bitbucket.org/cffi/cffi/changeset/88d2b9436efd/

Log:	Arithmetic using "void *" should work; at least it does in gcc
	without warning.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2050,7 +2050,7 @@
 static PyObject *
 _cdata_add_or_sub(PyObject *v, PyObject *w, int sign)
 {
-    Py_ssize_t i;
+    Py_ssize_t i, itemsize;
     CDataObject *cd;
     CTypeDescrObject *ctptr;
 
@@ -2073,14 +2073,19 @@
                      cd->c_type->ct_name);
         return NULL;
     }
-    if (ctptr->ct_itemdescr->ct_size < 0) {
-        PyErr_Format(PyExc_TypeError,
-                     "ctype '%s' points to items of unknown size",
-                     cd->c_type->ct_name);
-        return NULL;
-    }
-    return new_simple_cdata(cd->c_data + i * ctptr->ct_itemdescr->ct_size,
-                            ctptr);
+    itemsize = ctptr->ct_itemdescr->ct_size;
+    if (itemsize < 0) {
+        if (ctptr->ct_flags & CT_IS_VOID_PTR) {
+            itemsize = 1;
+        }
+        else {
+            PyErr_Format(PyExc_TypeError,
+                         "ctype '%s' points to items of unknown size",
+                         cd->c_type->ct_name);
+            return NULL;
+        }
+    }
+    return new_simple_cdata(cd->c_data + i * itemsize, ctptr);
 
  not_implemented:
     Py_INCREF(Py_NotImplemented);
@@ -2101,18 +2106,23 @@
         CDataObject *cdw = (CDataObject *)w;
         CTypeDescrObject *ct = cdw->c_type;
         Py_ssize_t diff;
+        Py_ssize_t itemsize;
 
         if (ct->ct_flags & CT_ARRAY)     /* ptr_to_T - array_of_T: ok */
             ct = (CTypeDescrObject *)ct->ct_stuff;
 
+        itemsize = ct->ct_itemdescr->ct_size;
+        if (ct->ct_flags & CT_IS_VOID_PTR)
+            itemsize = 1;
+
         if (ct != cdv->c_type || !(ct->ct_flags & CT_POINTER) ||
-                (ct->ct_itemdescr->ct_size <= 0)) {
+                (itemsize <= 0)) {
             PyErr_Format(PyExc_TypeError,
                          "cannot subtract cdata '%s' and cdata '%s'",
                          cdv->c_type->ct_name, ct->ct_name);
             return NULL;
         }
-        diff = (cdv->c_data - cdw->c_data) / ct->ct_itemdescr->ct_size;
+        diff = (cdv->c_data - cdw->c_data) / itemsize;
 #if PY_MAJOR_VERSION < 3
         return PyInt_FromSsize_t(diff);
 #else
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1642,9 +1642,6 @@
 def test_void_errors():
     py.test.raises(ValueError, alignof, new_void_type())
     py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None)
-    x = cast(new_pointer_type(new_void_type()), 42)
-    py.test.raises(TypeError, "x + 1")
-    py.test.raises(TypeError, "x - 1")
 
 def test_too_many_items():
     BChar = new_primitive_type("char")
@@ -3108,6 +3105,18 @@
     py.test.raises(TypeError, "p[1:5] = b'XYZT'")
     py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
 
+def test_void_p_arithmetic():
+    BVoid = new_void_type()
+    BInt = new_primitive_type("intptr_t")
+    p = cast(new_pointer_type(BVoid), 100000)
+    assert int(cast(BInt, p)) == 100000
+    assert int(cast(BInt, p + 42)) == 100042
+    assert int(cast(BInt, p - (-42))) == 100042
+    assert (p + 42) - p == 42
+    q = cast(new_pointer_type(new_primitive_type("char")), 100000)
+    py.test.raises(TypeError, "p - q")
+    py.test.raises(TypeError, "q - p")
+
 
 def test_version():
     # this test is here mostly for PyPy


More information about the pypy-commit mailing list