Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r64701:7b2e8cc68c61
Date: 2013-06-01 13:58 +0200
http://bitbucket.org/pypy/pypy/changeset/7b2e8cc68c61/

Log:    Update to cffi/263caa88878e

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
@@ -1,3 +1,4 @@
+import sys
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import unwrap_spec
 
@@ -113,6 +114,14 @@
 
 # ____________________________________________________________
 
+SF_MSVC_BITFIELDS = 1
+
+if sys.platform == 'win32':
+    DEFAULT_SFLAGS = SF_MSVC_BITFIELDS
+else:
+    DEFAULT_SFLAGS = 0
+
+
 @unwrap_spec(name=str)
 def new_struct_type(space, name):
     return ctypestruct.W_CTypeStruct(space, name)
@@ -121,9 +130,11 @@
 def new_union_type(space, name):
     return ctypestruct.W_CTypeUnion(space, name)
 
-@unwrap_spec(w_ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int)
+@unwrap_spec(w_ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int,
+             sflags=int)
 def complete_struct_or_union(space, w_ctype, w_fields, w_ignored=None,
-                             totalsize=-1, totalalignment=-1):
+                             totalsize=-1, totalalignment=-1,
+                             sflags=DEFAULT_SFLAGS):
     if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion)
             or w_ctype.size >= 0):
         raise OperationError(space.w_TypeError,
@@ -134,6 +145,8 @@
     alignment = 1
     boffset = 0         # this number is in *bits*, not bytes!
     boffsetmax = 0      # the maximum value of boffset, in bits too
+    prev_bitfield_size = 0
+    prev_bitfield_free = 0
     fields_w = space.listview(w_fields)
     fields_list = []
     fields_dict = {}
@@ -166,7 +179,15 @@
         # update the total alignment requirement, but skip it if the
         # field is an anonymous bitfield
         falign = ftype.alignof()
-        if alignment < falign and (fbitsize < 0 or fname != ''):
+        do_align = True
+        if fbitsize >= 0:
+            if (sflags & SF_MSVC_BITFIELDS) == 0:
+                # GCC: anonymous bitfields (of any size) don't cause alignment
+                do_align = (fname != '')
+            else:
+                # MSVC: zero-sized bitfields don't cause alignment
+                do_align = (fbitsize > 0)
+        if alignment < falign and do_align:
             alignment = falign
         #
         if fbitsize < 0:
@@ -208,6 +229,7 @@
                 fields_dict[fname] = fld
 
             boffset += ftype.size * 8
+            prev_bitfield_size = 0
 
         else:
             # this is the case of a bitfield
@@ -243,31 +265,67 @@
                     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
+                if (sflags & SF_MSVC_BITFIELDS) == 0:
+                    # GCC's notion of "ftype :0;"
+                    # pad boffset to a value aligned for "ftype"
+                    if boffset > field_offset_bytes * 8:
+                        field_offset_bytes += falign
+                        assert boffset < field_offset_bytes * 8
+                    boffset = field_offset_bytes * 8
+                else:
+                    # MSVC's notion of "ftype :0;
+                    # Mostly ignored.  It seems they only serve as
+                    # separator between other bitfields, to force them
+                    # into separate words.
+                    pass
+                prev_bitfield_size = 0
+
             else:
-                # 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 (sflags & SF_MSVC_BITFIELDS) == 0:
+                    # GCC's algorithm
 
-                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
+                    # 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:
+                        bitshift = bits_already_occupied
+                        assert bitshift >= 0
+                    boffset += fbitsize
+
                 else:
-                    bitshift = bits_already_occupied
+                    # MSVC's algorithm
+
+                    # A bitfield is considered as taking the full width
+                    # of their declared type.  It can share some bits
+                    # with the previous field only if it was also a
+                    # bitfield and used a type of the same size.
+                    if (prev_bitfield_size == ftype.size and
+                        prev_bitfield_free >= fbitsize):
+                        # yes: reuse
+                        bitshift = 8 * prev_bitfield_size - prev_bitfield_free
+                    else:
+                        # no: start a new full field
+                        boffset = (boffset + falign*8-1) & ~(falign*8-1)
+                        boffset += ftype.size * 8
+                        bitshift = 0
+                        prev_bitfield_size = ftype.size
+                        prev_bitfield_free = 8 * prev_bitfield_size
+                    #
+                    prev_bitfield_free -= fbitsize
+                    field_offset_bytes = boffset / 8 - ftype.size
 
                 fld = ctypestruct.W_CField(ftype, field_offset_bytes,
                                            bitshift, fbitsize)
                 fields_list.append(fld)
                 fields_dict[fname] = fld
-            
-                boffset += fbitsize
 
         if boffset > boffsetmax:
             boffsetmax = boffset
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,36 +2757,57 @@
     assert wr() is None
     py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
 
-def test_bitfield_as_gcc():
+def _test_bitfield_details(flag):
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
     BInt = new_primitive_type("int")
+    BUInt = new_primitive_type("unsigned 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
+                                       ('b1', BInt, 9),
+                                       ('b2', BUInt, 7),
+                                       ('c', BChar, -1)], -1, -1, -1, flag)
+    if flag == 0:   # gcc
+        assert typeoffsetof(BStruct, 'c') == (BChar, 3)
+        assert sizeof(BStruct) == 4
+    else:           # msvc
+        assert typeoffsetof(BStruct, 'c') == (BChar, 8)
+        assert sizeof(BStruct) == 12
     assert alignof(BStruct) == 4
     #
     BStruct = new_struct_type("foo2")
     complete_struct_or_union(BStruct, [('a', BChar, -1),
                                        ('',  BShort, 9),
-                                       ('c', BChar, -1)])
+                                       ('c', BChar, -1)], -1, -1, -1, flag)
     assert typeoffsetof(BStruct, 'c') == (BChar, 4)
-    assert sizeof(BStruct) == 5
-    assert alignof(BStruct) == 1
+    if flag == 0:   # gcc
+        assert sizeof(BStruct) == 5
+        assert alignof(BStruct) == 1
+    else:           # msvc
+        assert sizeof(BStruct) == 6
+        assert alignof(BStruct) == 2
     #
     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
+                                       ('c', BChar, -1)], -1, -1, -1, flag)
+    if flag == 0:   # gcc
+        assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+        assert sizeof(BStruct) == 5
+    else:           # msvc
+        assert typeoffsetof(BStruct, 'c') == (BChar, 1)
+        assert sizeof(BStruct) == 2
     assert alignof(BStruct) == 1
 
 
+def test_bitfield_as_gcc():
+    _test_bitfield_details(flag=0)
+
+def test_bitfield_as_msvc():
+    _test_bitfield_details(flag=1)
+
+
 def test_version():
     # this test is here mostly for PyPy
     assert __version__ == "0.7"
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to