]> git.sur5r.net Git - cc65/commitdiff
Made a C union declaration know the sizes of anonymous struct/union members when... 644/head
authorGreg King <gregdk@users.sf.net>
Sun, 13 May 2018 08:21:42 +0000 (04:21 -0400)
committerGreg King <gregdk@users.sf.net>
Sun, 13 May 2018 22:54:45 +0000 (18:54 -0400)
The bug was located, and the fix was written, by Francesco.

src/cc65/declare.c
test/val/anon-struct1.c [new file with mode: 0644]
test/val/anon-struct2.c [new file with mode: 0644]

index a6b2329051b3d339412a77640bd501f1a63b7bc7..19100781cb162d2c8a4be0871cd6ee24f31c7aa3 100644 (file)
@@ -656,13 +656,16 @@ static SymEntry* ParseUnionDecl (const char* Name)
             /* Check for fields without a name */
             if (Decl.Ident[0] == '\0') {
                 /* In cc65 mode, we allow anonymous structs/unions within
-                ** a struct.
+                ** a union.
                 */
                 if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) {
                     /* This is an anonymous struct or union. Copy the fields
                     ** into the current level.
                     */
-                    CopyAnonStructFields (&Decl, 0);
+                    FieldSize = CopyAnonStructFields (&Decl, 0);
+                    if (FieldSize > UnionSize) {
+                        UnionSize = FieldSize;
+                    }
 
                 } else {
                     /* A non bit-field without a name is legal but useless */
diff --git a/test/val/anon-struct1.c b/test/val/anon-struct1.c
new file mode 100644 (file)
index 0000000..9a737ad
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+  !!DESCRIPTION!! Make sure that structs/unions know the sizes of anonymous struct/union members
+  !!ORIGIN!!      cc65 regression tests
+  !!LICENCE!!     Public Domain
+  !!AUTHOR!!      Greg King
+*/
+
+/*
+  see https://github.com/cc65/cc65/issues/641
+*/
+
+#include <stdio.h>
+
+static unsigned char fails = 0;
+
+typedef struct {
+    short s1;
+    struct {
+        int i1;
+        long l1;
+        char c1;
+    };
+    char c2;
+} s1_t;
+
+typedef struct {
+    short s1;
+    union {
+        int i1;
+        long l1;
+        char c1;
+    };
+    char c2;
+} s2_t;
+
+typedef union {
+    short s1;
+    struct {
+        int i1;
+        long l1;
+        char c1;
+    };
+    char c2;
+} u1_t;
+
+typedef union {
+    short s1;
+    union {
+        int i1;
+        long l1;
+        char c1;
+    };
+    char c2;
+} u2_t;
+
+static s1_t s1;
+static s2_t s2;
+static u1_t u1;
+static u2_t u2;
+
+/* We use "variables" in the comparisons, so that we can avoid "constant
+** comparison" and "Unreachable code" warnings (the second one currently
+** can't be suppressed).
+*/
+
+static size_t const four = 4;
+static size_t const seven = 7;
+static size_t const ten = 10;
+
+int main(void)
+{
+    /* Check the types' sizes. */
+
+    if (sizeof (s1_t) != ten) {
+        printf("s1_t size is %u; it should be 10.\n", sizeof (s1_t));
+        ++fails;
+    }
+    if (sizeof (s2_t) != seven) {
+        printf("s2_t size is %u; it should be 7.\n", sizeof (s2_t));
+        ++fails;
+    }
+    if (sizeof (u1_t) != seven) {
+        printf("u1_t size is %u; it should be 7.\n", sizeof (u1_t));
+        ++fails;
+    }
+    if (sizeof (u2_t) != four) {
+        printf("u2_t size is %u; it should be 4.\n", sizeof (u2_t));
+        ++fails;
+    }
+
+    /* Check the variables' sizes. */
+
+    if (sizeof s1 != ten) {
+        printf("s1 size is %u; it should be 10.\n", sizeof s1);
+        ++fails;
+    }
+    if (sizeof s2 != seven) {
+        printf("s2 size is %u; it should be 7.\n", sizeof s2);
+        ++fails;
+    }
+    if (sizeof u1 != seven) {
+        printf("u1 size is %u; it should be 7.\n", sizeof u1);
+        ++fails;
+    }
+    if (sizeof u2 != four) {
+        printf("u2 size is %u; it should be 4.\n", sizeof u2);
+        ++fails;
+    }
+
+    return fails;
+}
diff --git a/test/val/anon-struct2.c b/test/val/anon-struct2.c
new file mode 100644 (file)
index 0000000..bdaddc8
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+  !!DESCRIPTION!! Make sure that the fields of anonymous structs/unions can be reached properly.
+  !!ORIGIN!!      cc65 regression tests
+  !!LICENCE!!     Public Domain
+  !!AUTHOR!!      Greg King
+*/
+
+#include <stddef.h>
+#include <stdio.h>
+
+static unsigned char fails = 0;
+
+typedef struct {
+    short s1;
+    struct {
+        char c1;
+        int i1;
+        long l1;
+    };
+    char c2;
+} s1_t;
+
+typedef struct {
+    char c2;
+    union {
+        int i1;
+        char c1;
+        long l1;
+    };
+    short s1;
+} s2_t;
+
+typedef union {
+    short s1;
+    struct {
+        int i1;
+        long l1;
+        char c1;
+    };
+    char c2;
+} u1_t;
+
+typedef union {
+    short s1;
+    union {
+        long l1;
+        char c1;
+        int i1;
+    };
+    char c2;
+} u2_t;
+
+typedef struct {
+    union {
+        short s1;
+        struct {
+            int i1;
+            long l1;
+            char c1;
+        };
+        char c2;
+    };
+    short s2;
+} s3_t;
+
+static s1_t s1;
+static s2_t s2;
+static u1_t u1;
+static u2_t u2;
+
+static long l2;
+static int i2;
+
+/* We use "variables" in the comparisons, so that we can avoid "constant
+** comparison" and "Unreachable code" warnings (the second one currently
+** can't be suppressed).
+*/
+
+static size_t const zero = 0;
+static size_t const one = 1;
+static size_t const three = 3;
+static size_t const five = 5;
+static size_t const six = 6;
+static size_t const seven = 7;
+static size_t const nine = 9;
+
+int main(void)
+{
+    /* Can cc65 see the names of members of anonymous structs/unions? */
+
+    l2 = s1.l1;
+    l2 = s2.l1;
+    l2 = u1.l1;
+    l2 = u2.l1;
+
+    i2 = s1.c1;
+    i2 = s1.c2;
+    i2 = s2.c1;
+    i2 = s2.c2;
+    i2 = u1.c1;
+    i2 = u1.c2;
+    i2 = u2.c1;
+    i2 = u2.c2;
+
+    /* Does cc65 use the correct offsets of
+    ** the members of anonymous structs/unions?
+    */
+
+    if (offsetof(s1_t, i1) != three) {
+        printf("The offset of s1.i1 is %u; it should be 3.\n", offsetof(s1_t, i1));
+        ++fails;
+    }
+    if (offsetof(s2_t, l1) != one) {
+        printf("The offset of s2.l1 is %u; it should be 1.\n", offsetof(s2_t, l1));
+        ++fails;
+    }
+    if (offsetof(u1_t, c1) != six) {
+        printf("The offset of u1.c1 is %u; it should be 6.\n", offsetof(u1_t, c1));
+        ++fails;
+    }
+    if (offsetof(u2_t, i1) != zero) {
+        printf("The offset of u2.i1 is %u; it should be 0.\n", offsetof(u2_t, i1));
+        ++fails;
+    }
+
+    /* Does cc65 use the correct offset of a member
+    ** that's later than an anonymous struct/union?
+    */
+
+    if (offsetof(s1_t, c2) != nine) {
+        printf("The offset of s1.c2 is %u; it should be 9.\n", offsetof(s1_t, c2));
+        ++fails;
+    }
+    if (offsetof(s2_t, s1) != five) {
+        printf("The offset of s2.s1 is %u; it should be 5.\n", offsetof(s2_t, s1));
+        ++fails;
+    }
+    if (offsetof(u1_t, c2) != zero) {
+        printf("The offset of u1.c2 is %u; it should be 0.\n", offsetof(u1_t, c2));
+        ++fails;
+    }
+    if (offsetof(u2_t, c2) != zero) {
+        printf("The offset of u2.c2 is %u; it should be 0.\n", offsetof(u2_t, c2));
+        ++fails;
+    }
+    if (offsetof(s3_t, s2) != seven) {
+        printf("The offset of s3.s2 is %u; it should be 7.\n", offsetof(s3_t, s2));
+        ++fails;
+    }
+
+    return fails;
+}