cc65 / cc65

cc65 - a freeware C compiler for 6502 based systems

Home Page:https://cc65.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[cc65] Wrong handling of enum/struct/union types without member lists in local declarations

acqn opened this issue · comments

commented

When a previous declaration that introduced the tag name of an enum(?)/struct/union is visible, only this one form out of all forms without their member lists as a local declaration redeclares a local enum(?)/struct/union type with the same tag name (that shadows the previous one) in the current scope:

struct TagName; /* <- enum(?)/struct/union type name terminated immediately with a semicolon */

Other forms without member lists just reuse the previous one without redeclaring any local types.

So with this example:

struct S { int a; } a;

void f(void)
{
    extern struct S a;          /* OK */
    struct S s;                 /* WRONG: cc65 declares f::S that shadows <filescope>::S, but should just reuse <filescope>::S */
    extern struct S a;          /* OK */
    {
        extern struct S a;      /* OK */
        union S;                /* WRONG: should be OK */
        extern union S x;       /* WRONG: should be OK */
        union S { char b; } s;  /* Recovered from previous errors, should be OK anyways */
    }
}

void g(void)
{
    struct S;               /* OK: Declares g::S that shadows <filescope>::S */
    extern struct S a;      /* WRONG: should be an error redeclaring <filescope>::a of a different type */
}
commented

Things get complicated when it comes to enum. Pre-C23 compiler extensions that support forward declaration of enum usually implement it similarly to struct/union. However, C23 requires it to be different from struct/union:

enum E { FIRST } c;
void h(void)
{
    enum E;          /* C23: No new type */
    extern enum E c; /* C23: OK no conflicts */
}

The C23 way to actually shadow a previously visible filescope enum with a new local enum is to redeclare it with a fixed underlying type (or a member list, of course):

enum E { FIRST } c;
void h(void)
{
    enum E : int;    /* C23: h::E shadows <filescope>::E */
    extern enum E c; /* C23: Error */
}