[pypy-commit] cffi default: Issue #193: if we use a struct between the first cdef() where it is

arigo noreply at buildbot.pypy.org
Wed May 20 14:31:40 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2062:2dfaf4b4f0aa
Date: 2015-05-20 14:32 +0200
http://bitbucket.org/cffi/cffi/changeset/2dfaf4b4f0aa/

Log:	Issue #193: if we use a struct between the first cdef() where it is
	declared and another cdef() where its fields are defined, then the
	definition was ignored.

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -109,6 +109,11 @@
             if override:
                 for cache in self._function_caches:
                     cache.clear()
+            finishlist = self._parser._recomplete
+            if finishlist:
+                self._parser._recomplete = []
+                for tp in finishlist:
+                    tp.finish_backend_type(self, finishlist)
 
     def dlopen(self, name, flags=0):
         """Load and return a dynamic library identified by 'name'.
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -101,6 +101,7 @@
         self._override = False
         self._packed = False
         self._int_constants = {}
+        self._recomplete = []
 
     def _parse(self, csource):
         csource, macros = _preprocess(csource)
@@ -555,6 +556,9 @@
                 raise NotImplementedError("%s: using both bitfields and '...;'"
                                           % (tp,))
         tp.packed = self._packed
+        if tp.completed:    # must be re-completed: it is not opaque any more
+            tp.completed = 0
+            self._recomplete.append(tp)
         return tp
 
     def _make_partial(self, tp, nested):
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -293,7 +293,7 @@
 
 class StructOrUnion(StructOrUnionOrEnum):
     fixedlayout = None
-    completed = False
+    completed = 0
     partial = False
     packed = False
 
@@ -351,12 +351,13 @@
                                           "for '%s'" % (self.name,))
             return
         BType = ffi._cached_btypes[self]
-        if self.fldtypes is None:
-            return    # not completing it: it's an opaque struct
         #
         self.completed = 1
         #
-        if self.fixedlayout is None:
+        if self.fldtypes is None:
+            pass    # not completing it: it's an opaque struct
+            #
+        elif self.fixedlayout is None:
             fldtypes = [tp.get_cached_btype(ffi, finishlist)
                         for tp in self.fldtypes]
             lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py
--- a/testing/cffi0/backend_tests.py
+++ b/testing/cffi0/backend_tests.py
@@ -1703,3 +1703,13 @@
         assert lib.DOT_HEX == 0x100
         assert lib.DOT_HEX2 == 0x10
         assert lib.DOT_UL == 1000
+
+    def test_opaque_struct_becomes_nonopaque(self):
+        # Issue #193: if we use a struct between the first cdef() where it is
+        # declared and another cdef() where its fields are defined, then the
+        # definition was ignored.
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("struct foo_s;")
+        py.test.raises(TypeError, ffi.new, "struct foo_s *")
+        ffi.cdef("struct foo_s { int x; };")
+        ffi.new("struct foo_s *")


More information about the pypy-commit mailing list