[pypy-commit] cffi default: Revert b84710ae130a again. Ensure we get a warning for every opaque

arigo pypy.commits at gmail.com
Thu Oct 20 04:20:44 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2795:94dc0b8274ee
Date: 2016-10-20 10:19 +0200
http://bitbucket.org/cffi/cffi/changeset/94dc0b8274ee/

Log:	Revert b84710ae130a again. Ensure we get a warning for every opaque
	enum, but then fall back to 'unsigned int'. See documentation for
	motivation.

diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -519,10 +519,18 @@
             smallest_value = min(self.enumvalues)
             largest_value = max(self.enumvalues)
         else:
-            raise api.CDefError("%r has no values explicitly defined: "
-                                "refusing to guess which integer type it is "
-                                "meant to be (unsigned/signed, int/long)"
-                % self._get_c_name())
+            import warnings
+            try:
+                # XXX!  The goal is to ensure that the warnings.warn()
+                # will not suppress the warning.  We want to get it
+                # several times if we reach this point several times.
+                __warningregistry__.clear()
+            except NameError:
+                pass
+            warnings.warn("%r has no values explicitly defined; "
+                          "guessing that it is equivalent to 'unsigned int'"
+                          % self._get_c_name())
+            smallest_value = largest_value = 0
         if smallest_value < 0:   # needs a signed type
             sign = 1
             candidate1 = PrimitiveType("int")
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -10,6 +10,13 @@
   in typedefs: ``typedef int foo_t[...];``.  It was already supported
   for global variables or structure fields.
 
+* I turned in v1.8 a warning from ``cffi/model.py`` into an error:
+  ``'enum xxx' has no values explicitly defined: refusing to guess which
+  integer type it is meant to be (unsigned/signed, int/long)``.  Now I'm
+  turning it back to a warning again; it seems that guessing that the
+  enum has size ``int`` is a 99%-safe bet.  (But not 100%, so it stays
+  as a warning.)
+
 
 v1.8.3
 ======
@@ -61,21 +68,6 @@
   argument (in older versions, a copy would be made).  This used to be
   a CPython-only optimization.
 
-* Turned a warning from ``cffi/model.py`` into an error: ``'enum xxx'
-  has no values explicitly defined: refusing to guess which integer type
-  it is meant to be (unsigned/signed, int/long)``.  The problem is that
-  CFFI can't handle opaque enums.  It can only handle enums as ``int``
-  or ``long`` integer types.  That seems to be enough in almost all
-  cases, but strictly speaking, C code *can* handle opaque enums without
-  knowing whether it is an ``int`` or a ``long``---i.e. without knowing
-  its size.  In this situation, in C you can pass pointers to such an
-  enum around, and that's about it.  CFFI can't do that so far.  There
-  is no fits-all solution, but try adding to the cdef: ``enum foo {
-  FOO_MAX_VALUE=1 };``; and, if using API mode, add ``#define
-  FOO_MAX_VALUE 1`` in the ``set_source()``.  Replace ``1`` with
-  ``9999999999`` in both places in the rare case where the enum needs to
-  fit values larger than an int.
-
 
 v1.7
 ====
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
@@ -1355,15 +1355,15 @@
         assert ffi.getctype("e1*") == 'e1 *'
 
     def test_opaque_enum(self):
+        import warnings
         ffi = FFI(backend=self.Backend())
         ffi.cdef("enum foo;")
-        from cffi import __version_info__
-        if __version_info__ < (1, 8):
-            py.test.skip("re-enable me in version 1.8")
-        e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
-        assert str(e.value) == (
-            "'enum foo' has no values explicitly defined: refusing to guess "
-            "which integer type it is meant to be (unsigned/signed, int/long)")
+        with warnings.catch_warnings(record=True) as log:
+            n = ffi.cast("enum foo", -1)
+            assert int(n) == 0xffffffff
+        assert str(log[0].message) == (
+            "'enum foo' has no values explicitly defined; "
+            "guessing that it is equivalent to 'unsigned int'")
 
     def test_new_ctype(self):
         ffi = FFI(backend=self.Backend())


More information about the pypy-commit mailing list