diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index a2bbf13dd..951ed9e5e 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -1225,6 +1225,15 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs /* Do we have an entry with this name already? */ SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name)); if (Entry) { + int CheckExtern = 0; + if ((Flags & SC_STRUCTFIELD) == 0) { + while (Entry && (Entry->Flags & SC_ALIAS) == SC_ALIAS) { + /* Get the aliased entry */ + Entry = Entry->V.A.Field; + /* Check for conflict with local storage class */ + CheckExtern = 1; + } + } /* We have a symbol with this name already */ if (HandleSymRedefinition (Entry, T, Flags)) { @@ -1234,19 +1243,14 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs if (SymIsDef (Entry) && (Flags & SC_DEF) == SC_DEF) { Error ("Multiple definition of '%s'", Entry->Name); Entry = 0; - } else if ((Flags & (SC_AUTO | SC_REGISTER)) != 0 && - (Entry->Flags & SC_EXTERN) != 0) { - /* Check for local storage class conflict */ - Error ("Declaration of '%s' with no linkage follows extern declaration", - Name); - Entry = 0; - } else { - /* If a static declaration follows a non-static declaration, - ** then it is an error. - */ - if ((Flags & SC_DEF) && - (Flags & SC_EXTERN) == 0 && - (Entry->Flags & SC_EXTERN) != 0) { + } else if (CheckExtern) { + if ((Flags & (SC_AUTO | SC_REGISTER)) != 0) { + Error ("Declaration of '%s' with no linkage follows extern declaration", Name); + Entry = 0; + } else if ((Flags & SC_DEF) != 0 && (Flags & SC_EXTERN) == 0) { + /* If a static declaration follows a non-static declaration, + ** then it is an error. + */ Error ("Static declaration of '%s' follows extern declaration", Name); Entry = 0; } @@ -1340,7 +1344,8 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) Name); Entry = 0; } else if ((Flags & SC_ESUTYPEMASK) != SC_TYPEDEF) { - /* If a static declaration follows a non-static declaration, then the result is undefined. + /* If a static declaration follows a non-static declaration, then + ** the result is undefined. ** Most compilers choose to either give an error at compile time, ** or remove the extern property for a link time error if used. */ @@ -1348,6 +1353,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) (Flags & SC_EXTERN) == 0 && (Entry->Flags & SC_EXTERN) != 0) { Error ("Static declaration of '%s' follows non-static declaration", Name); + Entry = 0; } else if ((Flags & SC_EXTERN) != 0 && (Entry->Owner == SymTab0 || (Entry->Flags & SC_DEF) != 0) && (Entry->Flags & SC_EXTERN) == 0) { @@ -1359,14 +1365,15 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) */ if (Entry->Owner == SymTab0) { if ((Flags & SC_STORAGE) == 0) { - /* Linkage must be unchanged. - ** The C standard specifies that a later extern declaration will be ignored, - ** and will use the previous linkage instead. Giving a warning for this case. + /* The C standard specifies that a later extern declaration will keep + ** the previously declared internal or external linkage unchanged. + ** Though not required by the standard, we are warning on this case. */ Flags &= ~SC_EXTERN; - Warning ("Extern declaration of '%s' follows static declaration, extern ignored", Name); + Warning ("Extern declaration of '%s' follows static declaration, linkage unchanged", Name); } else { Error ("Non-static declaration of '%s' follows static declaration", Name); + Entry = 0; } } else { Error ("Extern declaration of '%s' follows static declaration", Name); diff --git a/test/err/bug2162-none-extern-auto.c b/test/err/bug2162-none-extern-auto.c new file mode 100644 index 000000000..777fc48e7 --- /dev/null +++ b/test/err/bug2162-none-extern-auto.c @@ -0,0 +1,8 @@ +/* Bug #2162 - conflicting declarations in functions */ + +int main(void) +{ + extern int i; + int i = 42; /* Error */ + return i; +} diff --git a/test/err/bug2162-none-static-extern.c b/test/err/bug2162-none-static-extern.c new file mode 100644 index 000000000..cffb6a3bf --- /dev/null +++ b/test/err/bug2162-none-static-extern.c @@ -0,0 +1,8 @@ +/* Bug #2162 - conflicting declarations in functions */ + +int main(void) +{ + static int i = 42; + extern int i; /* Error */ + return i; +} diff --git a/test/err/bug2162-static-extern-auto.c b/test/err/bug2162-static-extern-auto.c new file mode 100644 index 000000000..08d91e0e1 --- /dev/null +++ b/test/err/bug2162-static-extern-auto.c @@ -0,0 +1,10 @@ +/* Bug #2162 - conflicting declarations in functions */ + +static int i; + +int main(void) +{ + extern int i; /* cc65 allows this */ + int i = 42; /* Error - if this were accepted, it would be confusing which object i refers to */ + return i; +} diff --git a/test/err/bug2162-static-static-extern.c b/test/err/bug2162-static-static-extern.c new file mode 100644 index 000000000..e0a536d6c --- /dev/null +++ b/test/err/bug2162-static-static-extern.c @@ -0,0 +1,10 @@ +/* Bug #2162 - conflicting declarations in functions */ + +static int i; + +int main(void) +{ + static int i = 42; /* OK - this shadows the i in file scope */ + extern int i; /* Error - if this were accepted, it would be confusing which object i refers to */ + return i; +}