Made a C union declaration know the sizes of anonymous struct/union members when it determines its size.
The bug was located, and the fix was written, by Francesco.
This commit is contained in:
parent
4e137cf9f5
commit
362b6afacf
3 changed files with 268 additions and 2 deletions
|
@ -656,13 +656,16 @@ static SymEntry* ParseUnionDecl (const char* Name)
|
||||||
/* Check for fields without a name */
|
/* Check for fields without a name */
|
||||||
if (Decl.Ident[0] == '\0') {
|
if (Decl.Ident[0] == '\0') {
|
||||||
/* In cc65 mode, we allow anonymous structs/unions within
|
/* In cc65 mode, we allow anonymous structs/unions within
|
||||||
** a struct.
|
** a union.
|
||||||
*/
|
*/
|
||||||
if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) {
|
if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) {
|
||||||
/* This is an anonymous struct or union. Copy the fields
|
/* This is an anonymous struct or union. Copy the fields
|
||||||
** into the current level.
|
** into the current level.
|
||||||
*/
|
*/
|
||||||
CopyAnonStructFields (&Decl, 0);
|
FieldSize = CopyAnonStructFields (&Decl, 0);
|
||||||
|
if (FieldSize > UnionSize) {
|
||||||
|
UnionSize = FieldSize;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* A non bit-field without a name is legal but useless */
|
/* A non bit-field without a name is legal but useless */
|
||||||
|
|
111
test/val/anon-struct1.c
Normal file
111
test/val/anon-struct1.c
Normal file
|
@ -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;
|
||||||
|
}
|
152
test/val/anon-struct2.c
Normal file
152
test/val/anon-struct2.c
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue