diff --git a/src/cc65/locals.c b/src/cc65/locals.c index ad36bded0..5f182f061 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -465,8 +465,8 @@ static void ParseOneDecl (const DeclSpec* Spec) /* The default storage class could be wrong. Just clear them */ Decl.StorageClass &= ~SC_STORAGEMASK; - /* This is always a declaration */ - Decl.StorageClass |= SC_DECL; + /* This is always an extern declaration */ + Decl.StorageClass |= SC_DECL | SC_EXTERN; } /* If we don't have a name, this was flagged as an error earlier. @@ -524,7 +524,9 @@ static void ParseOneDecl (const DeclSpec* Spec) if ((Decl.StorageClass & SC_EXTERN) == SC_EXTERN || (Decl.StorageClass & SC_FUNC) == SC_FUNC) { - /* Add the global symbol to the local symbol table */ + /* Add the global symbol to both of the global and local symbol + ** tables. + */ AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass); } else { /* Add the local symbol to the local symbol table */ diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h index bcf586510..52e590e2e 100644 --- a/src/cc65/symentry.h +++ b/src/cc65/symentry.h @@ -105,8 +105,8 @@ struct CodeEntry; #define SC_SPADJUSTMENT 0x400000U #define SC_GOTO_IND 0x800000U /* Indirect goto */ -#define SC_ALIAS 0x01000000U /* Alias of anonymous field */ -#define SC_FICTITIOUS 0x02000000U /* Symbol is fictitious */ +#define SC_ALIAS 0x01000000U /* Alias of global or anonymous field */ +#define SC_FICTITIOUS 0x02000000U /* Symbol is fictitious (for error recovery) */ #define SC_HAVEFAM 0x04000000U /* Type has a Flexible Array Member */ diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index aa4a9a44a..4d293ac3c 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -567,6 +567,11 @@ static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name) /* Try to find the symbol in this table */ SymEntry* E = FindSymInTable (Tab, Name, Hash); + while (E != 0 && (E->Flags & SC_ALIAS) == SC_ALIAS) { + /* Get the aliased entry */ + E = E->V.A.Field; + } + /* Bail out if we found it */ if (E != 0) { return E; @@ -1279,6 +1284,11 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs /* Generate the assembler name from the data label number */ Entry->V.L.Label = Offs; Entry->AsmName = xstrdup (LocalDataLabelName (Entry->V.L.Label)); + } else if ((Flags & SC_ALIAS) == SC_ALIAS) { + /* Just clear the info */ + Entry->V.A.Field = 0; + Entry->V.A.ANumber = 0; + Entry->V.A.Offs = 0; } else { Internal ("Invalid flags in AddLocalSym: %04X", Flags); } @@ -1296,13 +1306,26 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) /* Add an external or global symbol to the symbol table and return the entry */ { - /* Start from the local symbol table */ - SymTable* Tab = SymTab; + /* Add the new declaration to the global symbol table if no errors */ + SymTable* Tab = SymTab0; + + /* Only search this name in the local and global symbol tables */ + SymEntry* Entry = 0; + SymEntry* Alias = 0; + + if (SymTab != SymTab0) { + Alias = Entry = FindLocalSym (Name); + while (Entry && (Entry->Flags & SC_ALIAS) == SC_ALIAS) { + /* Get the aliased entry */ + Entry = Entry->V.A.Field; + } + } + + if (Entry == 0) { + Entry = FindGlobalSym (Name); + } - /* Do we have an entry with this name already? */ - SymEntry* Entry = FindSymInTree (Tab, Name); if (Entry) { - /* We have a symbol with this name already */ if (HandleSymRedefinition (Entry, T, Flags)) { Entry = 0; @@ -1317,7 +1340,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) ** declaration if both declarations are global, otherwise give an ** error. */ - if (Tab == SymTab0 && + if (SymTab == SymTab0 && (Flags & SC_EXTERN) == 0 && (Entry->Flags & SC_EXTERN) != 0) { Warning ("Static declaration of '%s' follows non-static declaration", Name); @@ -1353,12 +1376,9 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) /* Use the fail-safe table for fictitious symbols */ Tab = FailSafeTab; } - - } else if ((Flags & (SC_EXTERN | SC_FUNC)) != 0) { - /* Add the new declaration to the global symbol table instead */ - Tab = SymTab0; } - if (Entry == 0 || Entry->Owner != Tab) { + + if (Entry == 0) { /* Create a new entry */ Entry = NewSymEntry (Name, Flags); @@ -1376,6 +1396,13 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags) /* Add the entry to the symbol table */ AddSymEntry (Tab, Entry); + + } + + /* Add an alias of the global symbol to the local symbol table */ + if (Tab == SymTab0 && SymTab != SymTab0 && Entry->Owner != SymTab && Alias == 0) { + Alias = AddLocalSym (Name, T, SC_ALIAS, 0); + Alias->V.A.Field = Entry; } /* Return the entry */ diff --git a/test/val/extern.c b/test/val/extern.c new file mode 100644 index 000000000..6df3c9d50 --- /dev/null +++ b/test/val/extern.c @@ -0,0 +1,31 @@ +/* Test for shadowing and linkage of file-scope "static" and block-scope "extern" declarations */ + +static int g(int x); /* Generated functions with internal linkage are not always kept in cc65 */ + +int main(void) +{ + char f = 'f'; /* Shadows global "int f(void)" (if any) */ + char c = 'c'; /* Shadows global "int c" (if any) */ + { + void* f = 0; /* Shadows local "char f" */ + void* c = 0; /* Shadows local "char c" */ + { + int f(void); /* Shadows local "char f" and "void* f" */ + extern int g(int); /* Shadows global "int g(int x)" */ + extern int c; /* Shadows local "char c" and "void* c" */ + return f() ^ g(c); /* Link to global "int g(int x)" */ + } + } +} + +int c = 42; + +int f(void) +{ + return 42; +} + +int g(int x) +{ + return x; +}