From 750a527100526dfd33e31152819a87533ca95d1f Mon Sep 17 00:00:00 2001 From: Greg King Date: Sun, 12 Mar 2017 12:55:31 -0400 Subject: [PATCH] Made C's sizeof operator work with initialized void variables. Added regression tests that check cc65's handling of void variables. --- doc/cc65.sgml | 47 +++++++++++++--------- src/cc65/datatype.c | 7 +++- src/cc65/declare.c | 10 +++-- test/err/void-empty.c | 9 +++++ test/err/void-size2.c | 11 +++++ test/val/void-size1.c | 56 ++++++++++++++++++++++++++ testcode/lib/atari/displaylist.c | 69 +++++++++++++++----------------- 7 files changed, 147 insertions(+), 62 deletions(-) create mode 100644 test/err/void-empty.c create mode 100644 test/err/void-size2.c create mode 100644 test/val/void-size1.c diff --git a/doc/cc65.sgml b/doc/cc65.sgml index 80dba89b8..6a08cc3c3 100644 --- a/doc/cc65.sgml +++ b/doc/cc65.sgml @@ -4,7 +4,7 @@ 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 diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 8c9d6dcb0..2d54316cd 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -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: diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 163084835..7b543aa55 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -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 index 000000000..900918222 --- /dev/null +++ b/test/err/void-empty.c @@ -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 index 000000000..3d4f13322 --- /dev/null +++ b/test/err/void-size2.c @@ -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 index 000000000..0c2dccaa7 --- /dev/null +++ b/test/val/void-size1.c @@ -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; +} diff --git a/testcode/lib/atari/displaylist.c b/testcode/lib/atari/displaylist.c index 04c599878..ae1931e64 100644 --- a/testcode/lib/atari/displaylist.c +++ b/testcode/lib/atari/displaylist.c @@ -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; } - -- 2.39.5