Commits

Armin Rigo committed 263caa8

Fix MSVC bitfields in all tested cases.

Comments (0)

Files changed (3)

c/_cffi_backend.c

     for (i=0; i<nb_fields; i++) {
         PyObject *fname;
         CTypeDescrObject *ftype;
-        int fbitsize = -1, falign, foffset = -1;
+        int fbitsize = -1, falign, do_align, foffset = -1;
 
         if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|ii:list item",
                               &PyText_Type, &fname,
         falign = get_alignment(ftype);
         if (falign < 0)
             goto error;
-        if (alignment < falign && (fbitsize < 0 || PyText_GetSize(fname) > 0))
+
+        do_align = 1;
+        if (fbitsize >= 0) {
+            if (!(sflags & SF_MSVC_BITFIELDS)) {
+                /* GCC: anonymous bitfields (of any size) don't cause alignment */
+                do_align = PyText_GetSize(fname) > 0;
+            }
+            else {
+                /* MSVC: zero-sized bitfields don't cause alignment */
+                do_align = fbitsize > 0;
+            }
+        }
+        if (alignment < falign && do_align)
             alignment = falign;
 
         if (fbitsize < 0) {
                                  "field '%s.%s' is declared with :0",
                                  ct->ct_name, PyText_AS_UTF8(fname));
                 }
-                if (boffset > field_offset_bytes * 8) {
-                    field_offset_bytes += falign;
-                    assert(boffset < field_offset_bytes * 8);
+                if (!(sflags & SF_MSVC_BITFIELDS)) {
+                    /* 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;
                 }
-                boffset = field_offset_bytes * 8;   /* the only effect */
+                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. */
+                }
                 prev_bitfield_size = 0;
             }
             else {
                                        ('',  BShort, 9),
                                        ('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)], -1, -1, -1, flag)
-    assert typeoffsetof(BStruct, 'c') == (BChar, 4)
-    assert sizeof(BStruct) == 5
+    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
 
 

testing/test_ffi_backend.py

         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; int :0; 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)