]> git.sur5r.net Git - cc65/commitdiff
Made C's sizeof operator work with initialized void variables. 401/head
authorGreg King <gregdk@users.sf.net>
Sun, 12 Mar 2017 16:55:31 +0000 (12:55 -0400)
committerGreg King <gregdk@users.sf.net>
Sun, 12 Mar 2017 18:41:32 +0000 (14:41 -0400)
Added regression tests that check cc65's handling of void variables.

doc/cc65.sgml
src/cc65/datatype.c
src/cc65/declare.c
test/err/void-empty.c [new file with mode: 0644]
test/err/void-size2.c [new file with mode: 0644]
test/val/void-size1.c [new file with mode: 0644]
testcode/lib/atari/displaylist.c

index 80dba89b8b492e1ca85675a1f67b0c91fcf803ca..6a08cc3c395d118da661c40e653853b5c6707262 100644 (file)
@@ -4,7 +4,7 @@
 <title>cc65 Users Guide
 <author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
 <url url="mailto:gregdk@users.sf.net" name="Greg King">
-<date>2016-06-11
+<date>2017-02-27
 
 <abstract>
 cc65 is a C compiler for 6502 targets. It supports several 6502 based home
@@ -687,30 +687,37 @@ This cc65 version has some extensions to the ISO C standard.
        string.
        <p>
 
-<item>         cc65 allows the initialization of <tt/void/ variables. This may be
-       used to create variable structures that are more compatible with
-       interfaces written for assembler languages. Here is an example:
+<item>  cc65 allows the initialization of <tt/void/ variables. This may be
+        used to create arbitrary structures that are more compatible with
+        interfaces written for assembler languages. Here is an example:
 
-       <tscreen><verb>
-       void GCmd = {   (char)3, (unsigned)0x2000, (unsigned)0x3000 };
-       </verb></tscreen>
+        <tscreen><verb>
+        void GCmd = { (char)3, (unsigned)0x2000, (unsigned)0x3000 };
+        </verb></tscreen>
 
-       This will be translated as follows:
+        That will be translated as follows:
 
-       <tscreen><verb>
-       _GCmd:
-               .byte   3
-               .word   $2000
-               .word   $3000
-       </verb></tscreen>
+        <tscreen><verb>
+        _GCmd:
+                .byte   3
+                .word   $2000
+                .word   $3000
+        </verb></tscreen>
 
-       Since the variable is of type <tt/void/ you may not use it as is.
-       However, taking the address of the variable results in a <tt/void*/
-       which may be passed to any function expecting a pointer.
+        Since the variable is of type <tt/void/, you may not use it as-is.
+        However, taking the address of the variable results in a <tt/void*/
+        which may be passed to any function expecting a pointer.  Also, the
+        <tt/sizeof/ operator will give the length of the initializer:
 
-       See the <url url="geos.html" name="GEOS library document"> for examples
-       on how to use this feature.
-       <p>
+        <tscreen><verb>
+        GLen = sizeof GCmd;
+        </verb></tscreen>
+
+        will assign the value 5 to <tt/GLen/.
+
+        See the <url url="geos.html" name="GEOS library document"> for examples
+        on how to use that feature.
+        <p>
 
 <item>  cc65 implements flexible array struct members as defined in the C99 ISO
         standard. As an extension, these fields may be initialized. There are
index 8c9d6dcb00d6feb81cf12b7b2cc28316d7023c8f..2d54316cd9cbba88b28f97773107e48c8e132cac 100644 (file)
@@ -389,7 +389,10 @@ unsigned SizeOf (const Type* T)
     switch (UnqualifiedType (T->C)) {
 
         case T_VOID:
-            return 0;   /* Assume voids have size zero */
+            /* A void variable is a cc65 extension.
+            ** Get its size (in bytes).
+            */
+            return T->A.U;
 
         /* Beware: There's a chance that this triggers problems in other parts
            of the compiler. The solution is to fix the callers, because calling
@@ -438,7 +441,7 @@ unsigned SizeOf (const Type* T)
                 /* Array with unspecified size */
                 return 0;
             } else {
-                return T->A.L * SizeOf (T + 1);
+                return T->A.U * SizeOf (T + 1);
             }
 
         default:
index 1630848350892bafc71df8006490d3720c8e35c9..7b543aa55aa913c52ac21af66656a273c61021f6 100644 (file)
@@ -891,6 +891,7 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
         case TOK_VOID:
             NextToken ();
             D->Type[0].C = T_VOID;
+            D->Type[0].A.U = 0;
             D->Type[1].C = T_END;
             break;
 
@@ -2114,7 +2115,7 @@ NextMember:
 
 
 
-static unsigned ParseVoidInit (void)
+static unsigned ParseVoidInit (Type* T)
 /* Parse an initialization of a void variable (special cc65 extension).
 ** Return the number of bytes initialized.
 */
@@ -2181,6 +2182,9 @@ static unsigned ParseVoidInit (void)
     /* Closing brace */
     ConsumeRCurly ();
 
+    /* Number of bytes determined by initializer */
+    T->A.U = Size;
+
     /* Return the number of bytes initialized */
     return Size;
 }
@@ -2216,8 +2220,8 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
 
         case T_VOID:
             if (IS_Get (&Standard) == STD_CC65) {
-                /* Special cc65 extension in non ANSI mode */
-                return ParseVoidInit ();
+                /* Special cc65 extension in non-ANSI mode */
+                return ParseVoidInit (T);
             }
             /* FALLTHROUGH */
 
diff --git a/test/err/void-empty.c b/test/err/void-empty.c
new file mode 100644 (file)
index 0000000..9009182
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+  !!DESCRIPTION!! Uninitialized void variables
+  !!ORIGIN!!      cc65 regression tests
+  !!LICENCE!!     Public Domain
+  !!AUTHOR!!      Greg King
+*/
+
+void test;
+const void list;
diff --git a/test/err/void-size2.c b/test/err/void-size2.c
new file mode 100644 (file)
index 0000000..3d4f133
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+  !!DESCRIPTION!! Size of void cast
+  !!ORIGIN!!      cc65 regression tests
+  !!LICENCE!!     Public Domain
+  !!AUTHOR!!      Greg King
+*/
+
+unsigned test (void)
+{
+    return sizeof ((void)12345);
+}
diff --git a/test/val/void-size1.c b/test/val/void-size1.c
new file mode 100644 (file)
index 0000000..0c2dcca
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  !!DESCRIPTION!! Getting the size of a void-type variable (cc65 extension)
+  !!ORIGIN!!      cc65 regression tests
+  !!LICENCE!!     Public Domain
+  !!AUTHOR!!      Greg King
+*/
+
+static const void list1 = {
+    (char)1,
+    (char)2,
+    (char)3,
+    (char)4,
+    (char)5,
+    (char)6,
+    (char)7,
+    (char)8,
+    (char)9,
+    (char)0
+};
+
+static void list2 = {
+    1,
+    2,
+    3,
+    4,
+    5,
+    6,
+    7,
+    8,
+    9,
+    0
+};
+
+void list3 = {
+    (char)1,
+    (char)2,
+    (char)3,
+    (char)4,
+    &list1,
+    (char)6,
+    (char)7,
+    (char)8,
+    (char)9,
+    &list2
+};
+
+/* We know that the expression is constant; don't tell us. */
+
+#pragma warn (const-comparison, off)
+
+int main (void)
+{
+    return sizeof list1 != 10
+        || sizeof list2 != 20
+        || sizeof list3 != 12;
+}
index 04c5998786eb1cddb1b1c5f4c56af9ab5b82afd3..ae1931e64df042ede5534102349a44ed596a98a4 100644 (file)
@@ -1,59 +1,55 @@
 /*
-** testprogram for ANTIC instructions as defined in "_antic.h"
+** test program for ANTIC instructions as defined in "_antic.h"
 **
 ** 23-Feb-2017, Christian Krueger
 */
 
 #include <conio.h>
 #include <atari.h>
-#include <peekpoke.h>
-#include <string.h>
 
-// code is only for testing purposes, as screen and display list are not aligned
+// code is only for testing purposes, as screen and display list are not aligned,
 // and jumps not set!
 
 unsigned char DummyScreen[400];
 
 void DisplayList = {
-       DL_BLK1,
-       DL_BLK2,
-       DL_BLK3,
-       DL_BLK4,
-       DL_BLK5,
-       DL_BLK6,
-       DL_BLK7,
-       DL_DLI(DL_BLK8),
-       DL_LMS(DL_CHR40x8x1),
-       DummyScreen,
-       DL_HSCROL(DL_CHR40x10x1),
-       DL_VSCROL(DL_CHR40x8x4),
-       DL_CHR40x16x4,
-       DL_LMS(DL_HSCROL(DL_VSCROL(DL_DLI(DL_CHR20x8x2)))),
-       DummyScreen+120,
-       DL_CHR20x16x2,
-       DL_MAP40x8x4,
-       DL_MAP80x4x2,
-       DL_MAP80x4x4,
-       DL_MAP160x2x2,
-       DL_MAP160x1x2,
-       DL_MAP160x2x4,
-       DL_MAP160x1x4,
-       DL_MAP320x1x1, 
-       DL_JVB,
-       DL_JMP
+    DL_BLK1,
+    DL_BLK2,
+    DL_BLK3,
+    DL_BLK4,
+    DL_BLK5,
+    DL_BLK6,
+    DL_BLK7,
+    DL_DLI(DL_BLK8),
+    DL_LMS(DL_CHR40x8x1),
+    DummyScreen,
+    DL_HSCROL(DL_CHR40x10x1),
+    DL_VSCROL(DL_CHR40x8x4),
+    DL_CHR40x16x4,
+    DL_LMS(DL_HSCROL(DL_VSCROL(DL_DLI(DL_CHR20x8x2)))),
+    DummyScreen+120,
+    DL_CHR20x16x2,
+    DL_MAP40x8x4,
+    DL_MAP80x4x2,
+    DL_MAP80x4x4,
+    DL_MAP160x2x2,
+    DL_MAP160x1x2,
+    DL_MAP160x2x4,
+    DL_MAP160x1x4,
+    DL_MAP320x1x1,
+    DL_JVB,
+    DL_JMP
 };
 
-unsigned char dlend = 0;
 
+/* We know that the sizeof expression is constant; don't tell us. */
+
+#pragma warn (const-comparison, off)
 
 int
 main(void)
 {
-    // unfortunately "sizeof()" doesn't work with void data
-    // (Error: Size of data type is unknown)
-    // so we trick with the addresses at front and end...
-
-    int returnValue = (((unsigned int)&dlend-(unsigned int)&DisplayList) != 28);  // assure only one byte per instruction!
+    int returnValue = (sizeof DisplayList != 28);       // assure only one byte per instruction!
 
     clrscr();
     if (returnValue)
@@ -66,4 +62,3 @@ main(void)
 
     return returnValue;
 }
-