[pypy-commit] pypy py3k: merge default

pjenvey noreply at buildbot.pypy.org
Thu May 30 21:42:06 CEST 2013


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r64670:f76c1466005a
Date: 2013-05-30 12:36 -0700
http://bitbucket.org/pypy/pypy/changeset/f76c1466005a/

Log:	merge default

diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py
--- a/lib_pypy/cffi/vengine_cpy.py
+++ b/lib_pypy/cffi/vengine_cpy.py
@@ -156,6 +156,9 @@
         class FFILibrary(object):
             _cffi_python_module = module
             _cffi_ffi = self.ffi
+            _cffi_dir = []
+            def __dir__(self):
+                return FFILibrary._cffi_dir + list(self.__dict__)
         library = FFILibrary()
         module._cffi_setup(lst, ffiplatform.VerificationError, library)
         #
@@ -701,7 +704,8 @@
             return ptr[0]
         def setter(library, value):
             ptr[0] = value
-        setattr(library.__class__, name, property(getter, setter))
+        setattr(type(library), name, property(getter, setter))
+        type(library)._cffi_dir.append(name)
 
     # ----------
 
diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py
--- a/lib_pypy/cffi/vengine_gen.py
+++ b/lib_pypy/cffi/vengine_gen.py
@@ -74,6 +74,9 @@
         class FFILibrary(types.ModuleType):
             _cffi_generic_module = module
             _cffi_ffi = self.ffi
+            _cffi_dir = []
+            def __dir__(self):
+                return FFILibrary._cffi_dir
         library = FFILibrary("")
         #
         # finally, call the loaded_gen_xxx() functions.  This will set
@@ -168,21 +171,22 @@
             newfunction = self._load_constant(False, tp, name, module)
         else:
             indirections = []
-            if any(isinstance(type, model.StructOrUnion) for type in tp.args):
+            if any(isinstance(typ, model.StructOrUnion) for typ in tp.args):
                 indirect_args = []
-                for i, type in enumerate(tp.args):
-                    if isinstance(type, model.StructOrUnion):
-                        type = model.PointerType(type)
-                        indirections.append((i, type))
-                    indirect_args.append(type)
+                for i, typ in enumerate(tp.args):
+                    if isinstance(typ, model.StructOrUnion):
+                        typ = model.PointerType(typ)
+                        indirections.append((i, typ))
+                    indirect_args.append(typ)
                 tp = model.FunctionPtrType(tuple(indirect_args),
                                            tp.result, tp.ellipsis)
             BFunc = self.ffi._get_cached_btype(tp)
             wrappername = '_cffi_f_%s' % name
             newfunction = module.load_function(BFunc, wrappername)
-            for i, type in indirections:
-                newfunction = self._make_struct_wrapper(newfunction, i, type)
+            for i, typ in indirections:
+                newfunction = self._make_struct_wrapper(newfunction, i, typ)
         setattr(library, name, newfunction)
+        type(library)._cffi_dir.append(name)
 
     def _make_struct_wrapper(self, oldfunc, i, tp):
         backend = self.ffi._backend
@@ -390,6 +394,7 @@
         is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
         value = self._load_constant(is_int, tp, name, module)
         setattr(library, name, value)
+        type(library)._cffi_dir.append(name)
 
     # ----------
     # enums
@@ -437,6 +442,7 @@
     def _loaded_gen_enum(self, tp, name, module, library):
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
             setattr(library, enumerator, enumvalue)
+            type(library)._cffi_dir.append(enumerator)
 
     # ----------
     # macros: for now only for integers
@@ -450,6 +456,7 @@
     def _loaded_gen_macro(self, tp, name, module, library):
         value = self._load_constant(True, tp, name, module)
         setattr(library, name, value)
+        type(library)._cffi_dir.append(name)
 
     # ----------
     # global variables
@@ -475,6 +482,7 @@
                 BArray = self.ffi._get_cached_btype(tp)
                 value = self.ffi.cast(BArray, value)
             setattr(library, name, value)
+            type(library)._cffi_dir.append(name)
             return
         # remove ptr=<cdata 'int *'> from the library instance, and replace
         # it by a property on the class, which reads/writes into ptr[0].
@@ -486,7 +494,8 @@
             return ptr[0]
         def setter(library, value):
             ptr[0] = value
-        setattr(library.__class__, name, property(getter, setter))
+        setattr(type(library), name, property(getter, setter))
+        type(library)._cffi_dir.append(name)
 
 cffimod_header = r'''
 #include <stdio.h>
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -131,13 +131,12 @@
                                         " struct or union ctype"))
 
     is_union = isinstance(w_ctype, ctypestruct.W_CTypeUnion)
-    maxsize = 1
     alignment = 1
-    offset = 0
+    boffset = 0         # this number is in *bits*, not bytes!
+    boffsetmax = 0      # the maximum value of boffset, in bits too
     fields_w = space.listview(w_fields)
     fields_list = []
     fields_dict = {}
-    prev_bit_position = 0
     custom_field_pos = False
 
     for w_field in fields_w:
@@ -161,92 +160,129 @@
                     "field '%s.%s' has ctype '%s' of unknown size",
                                   w_ctype.name, fname, ftype.name)
         #
+        if is_union:
+            boffset = 0         # reset each field at offset 0
+        #
+        # update the total alignment requirement, but skip it if the
+        # field is an anonymous bitfield
         falign = ftype.alignof()
-        if alignment < falign:
+        if alignment < falign and (fbitsize < 0 or fname != ''):
             alignment = falign
         #
-        if foffset < 0:
+        if fbitsize < 0:
+            # not a bitfield: common case
+
+            if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length==0:
+                bs_flag = ctypestruct.W_CField.BS_EMPTY_ARRAY
+            else:
+                bs_flag = ctypestruct.W_CField.BS_REGULAR
+
             # align this field to its own 'falign' by inserting padding
-            offset = (offset + falign - 1) & ~(falign - 1)
+            boffset = (boffset + falign*8-1) & ~(falign*8-1)
+
+            if foffset >= 0:
+                # a forced field position: ignore the offset just computed,
+                # except to know if we must set 'custom_field_pos'
+                custom_field_pos |= (boffset != foffset * 8)
+                boffset = foffset * 8
+
+            if (fname == '' and
+                    isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)):
+                # a nested anonymous struct or union
+                srcfield2names = {}
+                for name, srcfld in ftype.fields_dict.items():
+                    srcfield2names[srcfld] = name
+                for srcfld in ftype.fields_list:
+                    fld = srcfld.make_shifted(boffset // 8)
+                    fields_list.append(fld)
+                    try:
+                        fields_dict[srcfield2names[srcfld]] = fld
+                    except KeyError:
+                        pass
+                # always forbid such structures from being passed by value
+                custom_field_pos = True
+            else:
+                # a regular field
+                fld = ctypestruct.W_CField(ftype, boffset // 8, bs_flag, -1)
+                fields_list.append(fld)
+                fields_dict[fname] = fld
+
+            boffset += ftype.size * 8
+
         else:
-            # a forced field position: ignore the offset just computed,
-            # except to know if we must set 'custom_field_pos'
-            custom_field_pos |= (offset != foffset)
-            offset = foffset
-        #
-        if fbitsize < 0 or (
-                fbitsize == 8 * ftype.size and not
-                isinstance(ftype, ctypeprim.W_CTypePrimitiveCharOrUniChar)):
-            fbitsize = -1
-            if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length == 0:
-                bitshift = ctypestruct.W_CField.BS_EMPTY_ARRAY
+            # this is the case of a bitfield
+
+            if foffset >= 0:
+                raise operationerrfmt(space.w_TypeError,
+                                      "field '%s.%s' is a bitfield, "
+                                      "but a fixed offset is specified",
+                                      w_ctype.name, fname)
+
+            if not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or
+                    isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or
+                    isinstance(ftype,ctypeprim.W_CTypePrimitiveCharOrUniChar)):
+                raise operationerrfmt(space.w_TypeError,
+                                      "field '%s.%s' declared as '%s' "
+                                      "cannot be a bit field",
+                                      w_ctype.name, fname, ftype.name)
+            if fbitsize > 8 * ftype.size:
+                raise operationerrfmt(space.w_TypeError,
+                                      "bit field '%s.%s' is declared '%s:%d',"
+                                      " which exceeds the width of the type",
+                                      w_ctype.name, fname,
+                                      ftype.name, fbitsize)
+
+            # compute the starting position of the theoretical field
+            # that covers a complete 'ftype', inside of which we will
+            # locate the real bitfield
+            field_offset_bytes = boffset // 8
+            field_offset_bytes &= ~(falign - 1)
+
+            if fbitsize == 0:
+                if fname != '':
+                    raise operationerrfmt(space.w_TypeError,
+                                          "field '%s.%s' is declared with :0",
+                                          w_ctype.name, fname)
+                if boffset > field_offset_bytes * 8:
+                    field_offset_bytes += falign
+                    assert boffset < field_offset_bytes * 8
+                boffset = field_offset_bytes * 8
             else:
-                bitshift = ctypestruct.W_CField.BS_REGULAR
-            prev_bit_position = 0
-        else:
-            if (not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or
-                     isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or
-                     isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)) or
-                fbitsize == 0 or
-                fbitsize > 8 * ftype.size):
-                raise operationerrfmt(space.w_TypeError,
-                                      "invalid bit field '%s'", fname)
-            if prev_bit_position > 0:
-                prev_field = fields_list[-1]
-                assert prev_field.bitshift >= 0
-                if prev_field.ctype.size != ftype.size:
-                    raise OperationError(space.w_NotImplementedError,
-                        space.wrap("consecutive bit fields should be "
-                                   "declared with a same-sized type"))
-                if prev_bit_position + fbitsize > 8 * ftype.size:
-                    prev_bit_position = 0
+                # Can the field start at the offset given by 'boffset'?  It
+                # can if it would entirely fit into an aligned ftype field.
+                bits_already_occupied = boffset - (field_offset_bytes * 8)
+
+                if bits_already_occupied + fbitsize > 8 * ftype.size:
+                    # it would not fit, we need to start at the next
+                    # allowed position
+                    field_offset_bytes += falign
+                    assert boffset < field_offset_bytes * 8
+                    boffset = field_offset_bytes * 8
+                    bitshift = 0
                 else:
-                    # we can share the same field as 'prev_field'
-                    offset = prev_field.offset
-            bitshift = prev_bit_position
-            if not is_union:
-                prev_bit_position += fbitsize
-        #
-        if (len(fname) == 0 and
-            isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)):
-            # a nested anonymous struct or union
-            srcfield2names = {}
-            for name, srcfld in ftype.fields_dict.items():
-                srcfield2names[srcfld] = name
-            for srcfld in ftype.fields_list:
-                fld = srcfld.make_shifted(offset)
+                    bitshift = bits_already_occupied
+
+                fld = ctypestruct.W_CField(ftype, field_offset_bytes,
+                                           bitshift, fbitsize)
                 fields_list.append(fld)
-                try:
-                    fields_dict[srcfield2names[srcfld]] = fld
-                except KeyError:
-                    pass
-            # always forbid such structures from being passed by value
-            custom_field_pos = True
-        else:
-            # a regular field
-            fld = ctypestruct.W_CField(ftype, offset, bitshift, fbitsize)
-            fields_list.append(fld)
-            fields_dict[fname] = fld
-        #
-        if maxsize < ftype.size:
-            maxsize = ftype.size
-        if not is_union:
-            offset += ftype.size
+                fields_dict[fname] = fld
+            
+                boffset += fbitsize
 
-    if is_union:
-        assert offset == 0
-        offset = maxsize
+        if boffset > boffsetmax:
+            boffsetmax = boffset
 
     # Like C, if the size of this structure would be zero, we compute it
     # as 1 instead.  But for ctypes support, we allow the manually-
     # specified totalsize to be zero in this case.
+    got = (boffsetmax + 7) // 8
     if totalsize < 0:
-        offset = (offset + alignment - 1) & ~(alignment - 1)
-        totalsize = offset or 1
-    elif totalsize < offset:
+        totalsize = (got + alignment - 1) & ~(alignment - 1)
+        totalsize = totalsize or 1
+    elif totalsize < got:
         raise operationerrfmt(space.w_TypeError,
                      "%s cannot be of size %d: there are fields at least "
-                     "up to %d", w_ctype.name, totalsize, offset)
+                     "up to %d", w_ctype.name, totalsize, got)
     if totalalignment < 0:
         totalalignment = alignment
 
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -2757,6 +2757,35 @@
     assert wr() is None
     py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
 
+def test_bitfield_as_gcc():
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo1")
+    complete_struct_or_union(BStruct, [('a', BChar, -1),
+                                       ('b', BInt, 9),
+                                       ('c', BChar, -1)])
+    assert typeoffsetof(BStruct, 'c') == (BChar, 3)
+    assert sizeof(BStruct) == 4
+    assert alignof(BStruct) == 4
+    #
+    BStruct = new_struct_type("foo2")
+    complete_struct_or_union(BStruct, [('a', BChar, -1),
+                                       ('',  BShort, 9),
+                                       ('c', BChar, -1)])
+    assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+    assert sizeof(BStruct) == 5
+    assert alignof(BStruct) == 1
+    #
+    BStruct = new_struct_type("foo2")
+    complete_struct_or_union(BStruct, [('a', BChar, -1),
+                                       ('',  BInt, 0),
+                                       ('',  BInt, 0),
+                                       ('c', BChar, -1)])
+    assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+    assert sizeof(BStruct) == 5
+    assert alignof(BStruct) == 1
+
 
 def test_version():
     # this test is here mostly for PyPy
diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py
--- a/pypy/module/_minimal_curses/fficurses.py
+++ b/pypy/module/_minimal_curses/fficurses.py
@@ -11,21 +11,50 @@
 from sys import platform
 import os.path
 
-_CYGWIN = platform == 'cygwin'
-_NCURSES_CURSES = os.path.isfile("/usr/include/ncurses/curses.h") 
+# We cannot trust ncurses5-config, it's broken in various ways in
+# various versions.  For example it might not list -ltinfo even though
+# it's needed, or --cflags might be completely empty.  On Ubuntu 10.04
+# it gives -I/usr/include/ncurses, which doesn't exist at all.  Crap.
 
-if _CYGWIN or _NCURSES_CURSES:
-    eci = ExternalCompilationInfo(
-        includes = ['ncurses/curses.h', 'ncurses/term.h'],
-        libraries = ['curses'],
-    )
-else:
-    eci = ExternalCompilationInfo(
-        includes = ['curses.h', 'term.h'],
-        libraries = ['curses'],
-    )
+def try_cflags():
+    yield ExternalCompilationInfo(includes=['curses.h', 'term.h'])
+    yield ExternalCompilationInfo(includes=['curses.h', 'term.h'],
+                                  include_dirs=['/usr/include/ncurses'])
+    yield ExternalCompilationInfo(includes=['ncurses/curses.h',
+                                            'ncurses/term.h'])
 
-rffi_platform.verify_eci(eci)
+def try_ldflags():
+    yield ExternalCompilationInfo(libraries=['curses'])
+    yield ExternalCompilationInfo(libraries=['curses', 'tinfo'])
+
+def try_tools():
+    try:
+        yield ExternalCompilationInfo.from_pkg_config("ncurses")
+    except Exception:
+        pass
+    try:
+        yield ExternalCompilationInfo.from_config_tool("ncurses5-config")
+    except Exception:
+        pass
+
+def try_eci():
+    for eci in try_tools():
+        yield eci.merge(ExternalCompilationInfo(includes=['curses.h',
+                                                          'term.h']))
+    for eci1 in try_cflags():
+        for eci2 in try_ldflags():
+            yield eci1.merge(eci2)
+
+def guess_eci():
+    for eci in try_eci():
+        class CConfig:
+            _compilation_info_ = eci
+            HAS = rffi_platform.Has("setupterm")
+        if rffi_platform.configure(CConfig)['HAS']:
+            return eci
+    raise ImportError("failed to guess where ncurses is installed")
+
+eci = guess_eci()
 
 
 INT = rffi.INT
diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py
--- a/pypy/module/_multiprocessing/interp_connection.py
+++ b/pypy/module/_multiprocessing/interp_connection.py
@@ -374,7 +374,7 @@
         return space.wrap(self)
 
     def descr_repr(self, space):
-        return self._repr(space, self.handle)
+        return self._repr(space, rffi.cast(rffi.INTPTR_T, self.handle))
 
     def is_valid(self):
         return self.handle != self.INVALID_HANDLE_VALUE
diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py
--- a/pypy/module/_multiprocessing/test/test_connection.py
+++ b/pypy/module/_multiprocessing/test/test_connection.py
@@ -67,7 +67,12 @@
         assert rhandle.readable
 
 class AppTestWinpipeConnection(BaseConnectionTest):
-    spaceconfig = dict(usemodules=('_multiprocessing', 'thread', 'signal'))
+    spaceconfig = {
+        "usemodules": [
+            '_multiprocessing', 'thread', 'signal', 'struct', 'array',
+            'itertools', '_socket', 'binascii',
+        ]
+    }
 
     def setup_class(cls):
         if sys.platform != "win32":
@@ -179,4 +184,4 @@
         assert repr(c) == '<read-write Connection, handle 1>'
         if hasattr(_multiprocessing, 'PipeConnection'):
             c = _multiprocessing.PipeConnection(1)
-            assert repr(c) == '<read-write Connection, handle 1>'
+            assert repr(c) == '<read-write PipeConnection, handle 1>'
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -1,24 +1,22 @@
+from rpython.rtyper.lltypesystem import lltype, rffi
+
 from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.interpreter.argument import Arguments
-from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.function import ClassMethod, Method, StaticMethod
 from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.function import (
-    BuiltinFunction, Method, StaticMethod, ClassMethod)
-from rpython.rtyper.lltypesystem import rffi, lltype
-from pypy.module.cpyext.pyobject import (PyObject, from_ref, make_ref,
-                                         make_typedescr, Py_DecRef)
+from pypy.interpreter.typedef import (
+    GetSetProperty, TypeDef, interp_attrproperty, interp_attrproperty_w)
 from pypy.module.cpyext.api import (
-    generic_cpy_call, cpython_api, PyObject, cpython_struct, METH_KEYWORDS,
-    METH_O, CONST_STRING, METH_CLASS, METH_STATIC, METH_COEXIST, METH_NOARGS,
-    METH_VARARGS, build_type_checkers, PyObjectFields, bootstrap_function)
-from pypy.module.cpyext.pyerrors import PyErr_Occurred
-from rpython.rlib.objectmodel import we_are_translated
+    CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O,
+    METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function,
+    build_type_checkers, cpython_api, cpython_struct, generic_cpy_call)
+from pypy.module.cpyext.pyobject import (
+    Py_DecRef, from_ref, make_ref, make_typedescr)
 
 PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction')
 PyCFunction = lltype.Ptr(lltype.FuncType([PyObject, PyObject], PyObject))
-PyCFunctionKwArgs = lltype.Ptr(lltype.FuncType([PyObject, PyObject, PyObject], PyObject))
+PyCFunctionKwArgs = lltype.Ptr(lltype.FuncType([PyObject, PyObject, PyObject],
+                                               PyObject))
 
 PyMethodDef = cpython_struct(
     'PyMethodDef',
@@ -89,9 +87,9 @@
                 self.name + "() takes no arguments"))
         elif flags & METH_O:
             if length != 1:
-                raise OperationError(space.w_TypeError,
-                        space.wrap("%s() takes exactly one argument (%d given)" %  (
-                        self.name, length)))
+                msg = "%s() takes exactly one argument (%d given)"
+                raise operationerrfmt(space.w_TypeError, msg,
+                                      self.name, length)
             w_arg = space.getitem(w_args, space.wrap(0))
             return generic_cpy_call(space, func, w_self, w_arg)
         elif flags & METH_VARARGS:
@@ -126,9 +124,12 @@
         return self.space.unwrap(self.descr_method_repr())
 
     def descr_method_repr(self):
-        return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space)))
+        return self.getrepr(self.space,
+                            "built-in method '%s' of '%s' object" %
+                            (self.name, self.w_objclass.getname(self.space)))
 
-PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject)
+PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers(
+    "CFunction", W_PyCFunctionObject)
 
 class W_PyCClassMethodObject(W_PyCFunctionObject):
     w_self = None
@@ -142,12 +143,14 @@
         return self.space.unwrap(self.descr_method_repr())
 
     def descr_method_repr(self):
-        return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space)))
+        return self.getrepr(self.space,
+                            "built-in method '%s' of '%s' object" %
+                            (self.name, self.w_objclass.getname(self.space)))
 
 
 class W_PyCWrapperObject(W_Root):
-    def __init__(self, space, pto, method_name, wrapper_func, wrapper_func_kwds,
-            doc, func):
+    def __init__(self, space, pto, method_name, wrapper_func,
+                 wrapper_func_kwds, doc, func):
         self.space = space
         self.method_name = method_name
         self.wrapper_func = wrapper_func
@@ -160,7 +163,8 @@
     def call(self, space, w_self, w_args, w_kw):
         if self.wrapper_func is None:
             assert self.wrapper_func_kwds is not None
-            return self.wrapper_func_kwds(space, w_self, w_args, self.func, w_kw)
+            return self.wrapper_func_kwds(space, w_self, w_args, self.func,
+                                          w_kw)
         if space.is_true(w_kw):
             raise operationerrfmt(
                 space.w_TypeError,
@@ -169,8 +173,9 @@
         return self.wrapper_func(space, w_self, w_args, self.func)
 
     def descr_method_repr(self):
-        return self.space.wrap("<slot wrapper '%s' of '%s' objects>" % (self.method_name,
-            self.w_objclass.getname(self.space)))
+        return self.space.wrap("<slot wrapper '%s' of '%s' objects>" %
+                               (self.method_name,
+                                self.w_objclass.getname(self.space)))
 
 def cwrapper_descr_call(space, w_self, __args__):
     self = space.interp_w(W_PyCWrapperObject, w_self)
@@ -240,7 +245,8 @@
     __get__ = interp2app(cclassmethod_descr_get),
     __call__ = interp2app(cmethod_descr_call),
     __name__ = interp_attrproperty('name', cls=W_PyCClassMethodObject),
-    __objclass__ = interp_attrproperty_w('w_objclass', cls=W_PyCClassMethodObject),
+    __objclass__ = interp_attrproperty_w('w_objclass',
+                                         cls=W_PyCClassMethodObject),
     __repr__ = interp2app(W_PyCClassMethodObject.descr_method_repr),
     )
 W_PyCClassMethodObject.typedef.acceptable_as_base_class = False
@@ -284,18 +290,19 @@
 def PyDescr_NewClassMethod(space, w_type, method):
     return space.wrap(W_PyCClassMethodObject(space, method, w_type))
 
-def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, wrapper_func_kwds,
-                       doc, func):
+def PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
+                       wrapper_func_kwds, doc, func):
     # not exactly the API sig
     return space.wrap(W_PyCWrapperObject(space, pto, method_name,
         wrapper_func, wrapper_func_kwds, doc, func))
 
 @cpython_api([lltype.Ptr(PyMethodDef), PyObject, CONST_STRING], PyObject)
 def Py_FindMethod(space, table, w_obj, name_ptr):
-    """Return a bound method object for an extension type implemented in C.  This
-    can be useful in the implementation of a tp_getattro or
-    tp_getattr handler that does not use the
-    PyObject_GenericGetAttr() function."""
+    """Return a bound method object for an extension type implemented in
+    C.  This can be useful in the implementation of a tp_getattro or
+    tp_getattr handler that does not use the PyObject_GenericGetAttr()
+    function.
+    """
     # XXX handle __doc__
 
     name = rffi.charp2str(name_ptr)
@@ -307,10 +314,12 @@
         while True:
             i = i + 1
             method = methods[i]
-            if not method.c_ml_name: break
+            if not method.c_ml_name:
+                break
             if name == "__methods__":
-                method_list_w.append(space.wrap(rffi.charp2str(method.c_ml_name)))
-            elif rffi.charp2str(method.c_ml_name) == name: # XXX expensive copying
+                method_list_w.append(
+                    space.wrap(rffi.charp2str(method.c_ml_name)))
+            elif rffi.charp2str(method.c_ml_name) == name: # XXX expensive copy
                 return space.wrap(W_PyCFunctionObject(space, method, w_obj))
     if name == "__methods__":
         return space.newlist(method_list_w)
diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py
--- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py
@@ -1,5 +1,5 @@
 # Generated by pypy/tool/import_cffi.py
-import py
+import py, sys
 from pypy.module.test_lib_pypy.cffi_tests import backend_tests, test_function, test_ownlib
 from cffi import FFI
 import _cffi_backend
@@ -37,3 +37,114 @@
         assert ffi.from_handle(p) is o
         assert ffi.from_handle(ffi.cast("char *", p)) is o
         py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
+
+
+class TestBitfield:
+    def check(self, source, expected_ofs_y, expected_align, expected_size):
+        ffi = FFI()
+        ffi.cdef("struct s1 { %s };" % source)
+        ctype = ffi.typeof("struct s1")
+        # verify the information with gcc
+        if sys.platform != "win32":
+            ffi1 = FFI()
+            ffi1.cdef("""
+                static const int Gofs_y, Galign, Gsize;
+                struct s1 *try_with_value(int fieldnum, long long value);
+            """)
+            fnames = [name for name, cfield in ctype.fields
+                           if name and cfield.bitsize > 0]
+            setters = ['case %d: s.%s = value; break;' % iname
+                       for iname in enumerate(fnames)]
+            lib = ffi1.verify("""
+                struct s1 { %s };
+                struct sa { char a; struct s1 b; };
+                #define Gofs_y  offsetof(struct s1, y)
+                #define Galign  offsetof(struct sa, b)
+                #define Gsize   sizeof(struct s1)
+                struct s1 *try_with_value(int fieldnum, long long value)
+                {
+                    static struct s1 s;
+                    memset(&s, 0, sizeof(s));
+                    switch (fieldnum) { %s }
+                    return &s;
+                }
+            """ % (source, ' '.join(setters)))
+            assert lib.Gofs_y == expected_ofs_y
+            assert lib.Galign == expected_align
+            assert lib.Gsize  == expected_size
+        else:
+            lib = None
+            fnames = None
+        # the real test follows
+        assert ffi.offsetof("struct s1", "y") == expected_ofs_y
+        assert ffi.alignof("struct s1") == expected_align
+        assert ffi.sizeof("struct s1") == expected_size
+        # compare the actual storage of the two
+        for name, cfield in ctype.fields:
+            if cfield.bitsize < 0 or not name:
+                continue
+            if int(ffi.cast(cfield.type, -1)) == -1:   # signed
+                min_value = -(1 << (cfield.bitsize-1))
+                max_value = (1 << (cfield.bitsize-1)) - 1
+            else:
+                min_value = 0
+                max_value = (1 << cfield.bitsize) - 1
+            for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729,
+                     -1,-2,-4,-8,-16,-128,-2813,-89728,-981729]:
+                if min_value <= t <= max_value:
+                    self._fieldcheck(ffi, lib, fnames, name, t)
+
+    def _fieldcheck(self, ffi, lib, fnames, name, value):
+        s = ffi.new("struct s1 *")
+        setattr(s, name, value)
+        assert getattr(s, name) == value
+        raw1 = bytes(ffi.buffer(s))
+        if lib is not None:
+            t = lib.try_with_value(fnames.index(name), value)
+            raw2 = bytes(ffi.buffer(t, len(raw1)))
+            assert raw1 == raw2
+
+    def test_bitfield_basic(self):
+        self.check("int a; int b:9; int c:20; int y;", 8, 4, 12)
+        self.check("int a; short b:9; short c:7; int y;", 8, 4, 12)
+        self.check("int a; short b:9; short c:9; int y;", 8, 4, 12)
+
+    def test_bitfield_reuse_if_enough_space(self):
+        self.check("int a:2; char y;", 1, 4, 4)
+        self.check("int a:1; char b  ; int c:1; char y;", 3, 4, 4)
+        self.check("int a:1; char b:8; int c:1; char y;", 3, 4, 4)
+        self.check("char a; int b:9; char y;", 3, 4, 4)
+        self.check("char a; short b:9; char y;", 4, 2, 6)
+        self.check("int a:2; char b:6; char y;", 1, 4, 4)
+        self.check("int a:2; char b:7; char y;", 2, 4, 4)
+        self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8)
+        self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4)
+
+    def test_bitfield_anonymous_no_align(self):
+        L = FFI().alignof("long long")
+        self.check("char y; int :1;", 0, 1, 2)
+        self.check("char x; int z:1; char y;", 2, 4, 4)
+        self.check("char x; int  :1; char y;", 2, 1, 3)
+        self.check("char x; long long z:48; char y;", 7, L, 8)
+        self.check("char x; long long  :48; char y;", 7, 1, 8)
+        self.check("char x; long long z:56; char y;", 8, L, 8 + L)
+        self.check("char x; long long  :56; char y;", 8, 1, 9)
+        self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
+        self.check("char x; long long  :57; char y;", L + 8, 1, L + 9)
+
+    def test_bitfield_zero(self):
+        L = FFI().alignof("long long")
+        self.check("char y; int :0;", 0, 1, 4)
+        self.check("char x; int :0; char y;", 4, 1, 5)
+        self.check("char x; long long :0; char y;", L, 1, L + 1)
+        self.check("short x, y; int :0; int :0;", 2, 2, 4)
+        self.check("char x; int :0; short b:1; char y;", 5, 2, 6)
+
+    def test_error_cases(self):
+        ffi = FFI()
+        py.test.raises(TypeError,
+            'ffi.cdef("struct s1 { float x:1; };"); ffi.new("struct s1 *")')
+        py.test.raises(TypeError,
+            'ffi.cdef("struct s2 { char x:0; };"); ffi.new("struct s2 *")')
+        py.test.raises(TypeError,
+            'ffi.cdef("struct s3 { char x:9; };"); ffi.new("struct s3 *")')
diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py
--- a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py
@@ -1620,3 +1620,18 @@
     ffi.cdef("int f(void *);")
     lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }")
     assert lib.f(b"foobar") == ord(b"f")
+
+def test_dir():
+    ffi = FFI()
+    ffi.cdef("""void somefunc(void);
+                extern int somevar, somearray[2];
+                static char *const sv2;
+                enum my_e { AA, BB, ... };
+                #define FOO ...""")
+    lib = ffi.verify("""void somefunc(void) { }
+                        int somevar, somearray[2];
+                        #define sv2 "text"
+                        enum my_e { AA, BB };
+                        #define FOO 42""")
+    assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray',
+                        'somefunc', 'somevar', 'sv2']
diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py
--- a/pypy/objspace/std/stdtypedef.py
+++ b/pypy/objspace/std/stdtypedef.py
@@ -147,21 +147,12 @@
     else:
         plural = ''
     return "unsupported operand type%s for %%s: %s" % (
-        plural, ', '.join(["'%s'"] * nbargs))
+        plural, ', '.join(["'%T'"] * nbargs))
 _gettypeerrormsg._annspecialcase_ = 'specialize:memo'
 
-def _gettypenames(space, *args_w):
-    if args_w:
-        typename = space.type(args_w[-1]).getname(space)
-        return _gettypenames(space, *args_w[:-1]) + (typename,)
-    return ()
-_gettypenames._always_inline_ = True
-
 def gettypeerror(space, operatorsymbol, *args_w):
     msg = _gettypeerrormsg(len(args_w))
-    type_names = _gettypenames(space, *args_w)
-    return operationerrfmt(space.w_TypeError, msg,
-                           operatorsymbol, *type_names)
+    return operationerrfmt(space.w_TypeError, msg, operatorsymbol, *args_w)
 
 def make_perform_trampoline(prefix, exprargs, expr, miniglobals,  multimethod, selfindex=0,
                             allow_NotImplemented_results=False):
diff --git a/rpython/translator/tool/cbuild.py b/rpython/translator/tool/cbuild.py
--- a/rpython/translator/tool/cbuild.py
+++ b/rpython/translator/tool/cbuild.py
@@ -1,5 +1,5 @@
 import py
-import sys
+import sys, subprocess
 
 from rpython.translator.platform import host
 from rpython.tool.udir import udir
@@ -99,6 +99,7 @@
             return platform
         return self._platform
 
+    @classmethod
     def from_compiler_flags(cls, flags):
         """Returns a new ExternalCompilationInfo instance by parsing
         the string 'flags', which is in the typical Unix compiler flags
@@ -124,8 +125,8 @@
         return cls(pre_include_bits=pre_include_bits,
                    include_dirs=include_dirs,
                    compile_extra=compile_extra)
-    from_compiler_flags = classmethod(from_compiler_flags)
 
+    @classmethod
     def from_linker_flags(cls, flags):
         """Returns a new ExternalCompilationInfo instance by parsing
         the string 'flags', which is in the typical Unix linker flags
@@ -146,8 +147,8 @@
         return cls(libraries=libraries,
                    library_dirs=library_dirs,
                    link_extra=link_extra)
-    from_linker_flags = classmethod(from_linker_flags)
 
+    @classmethod
     def from_config_tool(cls, execonfigtool):
         """Returns a new ExternalCompilationInfo instance by executing
         the 'execonfigtool' with --cflags and --libs arguments."""
@@ -156,12 +157,29 @@
             raise ImportError("cannot find %r" % (execonfigtool,))
             # we raise ImportError to be nice to the pypy.config.pypyoption
             # logic of skipping modules depending on non-installed libs
-        cflags = py.process.cmdexec('"%s" --cflags' % (str(path),))
+        return cls._run_config_tool('"%s"' % (str(path),))
+
+    @classmethod
+    def from_pkg_config(cls, pkgname):
+        """Returns a new ExternalCompilationInfo instance by executing
+        'pkg-config <pkgname>' with --cflags and --libs arguments."""
+        assert isinstance(pkgname, str)
+        try:
+            popen = subprocess.Popen(['pkg-config', pkgname, '--exists'])
+            result = popen.wait()
+        except OSError:
+            result = -1
+        if result != 0:
+            raise ImportError("failed: 'pkg-config %s --exists'" % pkgname)
+        return cls._run_config_tool('pkg-config "%s"' % pkgname)
+
+    @classmethod
+    def _run_config_tool(cls, command):
+        cflags = py.process.cmdexec('%s --cflags' % command)
         eci1 = cls.from_compiler_flags(cflags)
-        libs = py.process.cmdexec('"%s" --libs' % (str(path),))
+        libs = py.process.cmdexec('%s --libs' % command)
         eci2 = cls.from_linker_flags(libs)
         return eci1.merge(eci2)
-    from_config_tool = classmethod(from_config_tool)
 
     def _value(self):
         return tuple([getattr(self, x)
diff --git a/rpython/translator/tool/test/test_cbuild.py b/rpython/translator/tool/test/test_cbuild.py
--- a/rpython/translator/tool/test/test_cbuild.py
+++ b/rpython/translator/tool/test/test_cbuild.py
@@ -127,6 +127,18 @@
                        ExternalCompilationInfo.from_config_tool,
                        'dxowqbncpqympqhe-config')
 
+    def test_from_pkg_config(self):
+        try:
+            cmd = ['pkg-config', 'ncurses', '--exists']
+            popen = Popen(cmd)
+            result = popen.wait()
+        except OSError:
+            result = -1
+        if result != 0:
+            py.test.skip("failed: %r" % (' '.join(cmd),))
+        eci = ExternalCompilationInfo.from_pkg_config('ncurses')
+        assert 'ncurses' in eci.libraries
+
     def test_platforms(self):
         from rpython.translator.platform import Platform
 


More information about the pypy-commit mailing list