diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 9f1ab29f5..48a5c29d3 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -157,7 +157,7 @@ static void Parse (void) CurTok.Tok == TOK_ASSIGN))) { /* We will allocate storage */ - Decl.StorageClass |= SC_STORAGE | SC_DEF; + Decl.StorageClass |= SC_STORAGE; } /* If this is a function declarator that is not followed by a comma @@ -190,6 +190,13 @@ static void Parse (void) /* Allow initialization */ if (CurTok.Tok == TOK_ASSIGN) { + /* This is a definition */ + if (SymIsDef (Entry)) { + Error ("Global variable `%s' has already been defined", + Entry->Name); + } + Entry->Flags |= SC_DEF; + /* We cannot initialize types of unknown size, or ** void types in ISO modes. */ @@ -237,18 +244,14 @@ static void Parse (void) Entry->Flags &= ~(SC_STORAGE | SC_DEF); } - /* Allocate storage if it is still needed */ - if (Entry->Flags & SC_STORAGE) { - - /* Switch to the BSS segment */ - g_usebss (); - - /* Define a label */ - g_defgloblabel (Entry->Name); - - /* Allocate space for uninitialized variable */ - g_res (Size); - } + /* A global (including static) uninitialized variable + ** is only a tentative definition. For example, this is valid: + ** int i; + ** int i; + ** static int j; + ** static int j = 42; + ** Code for these will be generated in FinishCompile. + */ } } @@ -303,7 +306,7 @@ void Compile (const char* FileName) struct tm* TM; /* Since strftime is locale dependent, we need the abbreviated month names - ** in english. + ** in English. */ static const char MonthNames[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -400,20 +403,26 @@ void Compile (const char* FileName) void FinishCompile (void) /* Emit literals, externals, debug info, do cleanup and optimizations */ { - SymTable* SymTab; - SymEntry* Func; + SymEntry* Entry; - /* Walk over all functions, doing cleanup, optimizations ... */ - SymTab = GetGlobalSymTab (); - Func = SymTab->SymHead; - while (Func) { - if (SymIsOutputFunc (Func)) { + /* Walk over all global symbols: + ** - for functions do cleanup, optimizations ... + ** - generate code for uninitialized global variables + */ + for (Entry = GetGlobalSymTab ()->SymHead; Entry; Entry = Entry->NextSym) { + if (SymIsOutputFunc (Entry)) { /* Function which is defined and referenced or extern */ - MoveLiteralPool (Func->V.F.LitPool); - CS_MergeLabels (Func->V.F.Seg->Code); - RunOpt (Func->V.F.Seg->Code); + MoveLiteralPool (Entry->V.F.LitPool); + CS_MergeLabels (Entry->V.F.Seg->Code); + RunOpt (Entry->V.F.Seg->Code); + } else if ((Entry->Flags & (SC_STORAGE | SC_DEF | SC_STATIC)) == (SC_STORAGE | SC_STATIC)) { + /* Tentative definition of uninitialized global variable */ + g_usebss (); + g_defgloblabel (Entry->Name); + g_res (SizeOf (Entry->Type)); + /* Mark as defined, so that it will be exported not imported */ + Entry->Flags |= SC_DEF; } - Func = Func->NextSym; } /* Output the literal pool */ diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index fdf459873..3275332c5 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -821,7 +821,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) } /* An extern declaration must not change the current linkage. */ - if (IsFunc || (Flags & (SC_EXTERN | SC_DEF)) == SC_EXTERN) { + if (IsFunc || (Flags & (SC_EXTERN | SC_STORAGE)) == SC_EXTERN) { Flags &= ~SC_EXTERN; } diff --git a/test/err/duplicate-global-static.c b/test/err/duplicate-global-static.c new file mode 100644 index 000000000..6aa27f5b7 --- /dev/null +++ b/test/err/duplicate-global-static.c @@ -0,0 +1,18 @@ +/* + !!DESCRIPTION!! global duplicated with static variable + !!ORIGIN!! cc65 regression tests + !!LICENCE!! Public Domain + !!AUTHOR!! Piotr Fusik +*/ + +/* + see: https://github.com/cc65/cc65/issues/191 +*/ + +int n = 0; +static int n = 0; /* should give an error */ + +int main(void) +{ + return n; +} diff --git a/test/err/duplicate-global.c b/test/err/duplicate-global.c new file mode 100644 index 000000000..bd4fcc24a --- /dev/null +++ b/test/err/duplicate-global.c @@ -0,0 +1,20 @@ +/* + !!DESCRIPTION!! duplicate globals + !!ORIGIN!! cc65 regression tests + !!LICENCE!! Public Domain + !!AUTHOR!! Piotr Fusik +*/ + +/* + see: https://github.com/cc65/cc65/issues/191 +*/ + +#pragma warn(error, on) + +int n = 0; +int n = 0; /* should give an error */ + +int main(void) +{ + return n; +} diff --git a/test/err/duplicate-static-global.c b/test/err/duplicate-static-global.c new file mode 100644 index 000000000..6e5e70a37 --- /dev/null +++ b/test/err/duplicate-static-global.c @@ -0,0 +1,18 @@ +/* + !!DESCRIPTION!! static duplicated with global variable + !!ORIGIN!! cc65 regression tests + !!LICENCE!! Public Domain + !!AUTHOR!! Piotr Fusik +*/ + +/* + see: https://github.com/cc65/cc65/issues/191 +*/ + +static int n = 0; +int n = 0; /* should give an error */ + +int main(void) +{ + return n; +} diff --git a/test/err/duplicate-static.c b/test/err/duplicate-static.c new file mode 100644 index 000000000..394cc1e09 --- /dev/null +++ b/test/err/duplicate-static.c @@ -0,0 +1,20 @@ +/* + !!DESCRIPTION!! duplicate static variables + !!ORIGIN!! cc65 regression tests + !!LICENCE!! Public Domain + !!AUTHOR!! Piotr Fusik +*/ + +/* + see: https://github.com/cc65/cc65/issues/191 +*/ + +#pragma warn(error, on) + +static int n = 0; +static int n = 0; /* should give an error */ + +int main(void) +{ + return n; +} diff --git a/test/val/static-fwd-decl.c b/test/val/static-fwd-decl.c new file mode 100644 index 000000000..420640d97 --- /dev/null +++ b/test/val/static-fwd-decl.c @@ -0,0 +1,35 @@ +/* + !!DESCRIPTION!! static forward declarations + !!ORIGIN!! cc65 regression tests + !!LICENCE!! Public Domain + !!AUTHOR!! Bob Andrews +*/ + +/* + see: https://github.com/cc65/cc65/issues/204 +*/ + +#pragma warn(error, on) + +typedef struct _DIRMENU +{ + const char *name; + struct _DIRMENU *dest; +} DIRMENU; + +static DIRMENU rmenu; + +static DIRMENU lmenu = { + "left", + &rmenu +}; + +static DIRMENU rmenu = { + "right", + &lmenu +}; + +int main(void) +{ + return lmenu.dest == &rmenu && rmenu.dest == &lmenu ? 0 : 1; +}