1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-01 13:41:34 +00:00

Improved error handling with symbol redefinitions.

This commit is contained in:
acqn 2020-07-29 18:07:16 +08:00 committed by Oliver Schmidt
parent 92de4fa0d0
commit d6d667a688

View File

@ -93,6 +93,7 @@ static SymTable* TagTab0 = 0;
static SymTable* TagTab = 0;
static SymTable* LabelTab = 0;
static SymTable* SPAdjustTab = 0;
static SymTable* FailSafeTab = 0; /* For errors */
/*****************************************************************************/
@ -141,7 +142,6 @@ static void FreeSymTable (SymTable* S)
}
/*****************************************************************************/
/* Check symbols in a table */
/*****************************************************************************/
@ -228,6 +228,9 @@ void EnterGlobalLevel (void)
/* Create and assign the table of SP adjustment symbols */
SPAdjustTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
/* Create and assign the table of fictitious symbols used with errors */
FailSafeTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
}
@ -523,6 +526,111 @@ SymEntry* FindStructField (const Type* T, const char* Name)
static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags)
/* Check and handle redefinition of existing symbols.
** Return ture if there *is* an error.
*/
{
/* Get the type info of the existing symbol */
Type* E_Type = Entry->Type;
unsigned E_SCType = Entry->Flags & SC_TYPEMASK;
unsigned SCType = Flags & SC_TYPEMASK;
/* Some symbols may be redeclared if certain requirements are met */
if (IsTypeArray (T) && IsTypeArray (E_Type)) {
/* Get the array sizes */
long Size = GetElementCount (T);
long ESize = GetElementCount (E_Type);
/* If we are handling arrays, the old entry or the new entry may be
** an incomplete declaration. Accept this, and if the exsting entry
** is incomplete, complete it.
*/
if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
TypeCmp (T + 1, E_Type + 1) < TC_EQUAL) {
/* Types not identical: Conflicting types */
Error ("Conflicting array types for '%s[]'", Entry->Name);
Entry = 0;
} else {
/* Check if we have a size in the existing definition */
if (ESize == UNSPECIFIED) {
/* Existing, size not given, use size from new def */
SetElementCount (E_Type, Size);
}
}
} else {
/* We have a symbol with this name already */
if ((Entry->Flags & SC_FUNC) == SC_FUNC) {
/* In case of a function, use the new type descriptor, since it
** contains pointers to the new symbol tables that are needed if
** an actual function definition follows. Be sure not to use the
** new descriptor if it contains a function declaration with an
** empty parameter list.
*/
if (IsTypeFunc (T)) {
/* New type must be identical */
if (TypeCmp (Entry->Type, T) < TC_EQUAL) {
Error ("Conflicting function types for '%s'", Entry->Name);
Entry = 0;
} else {
/* Get the function descriptor from the new type */
FuncDesc* F = GetFuncDesc (T);
/* Use this new function descriptor if it doesn't contain
** an empty parameter list.
*/
if ((F->Flags & FD_EMPTY) == 0) {
Entry->V.F.Func = F;
SetFuncDesc (E_Type, F);
}
}
} else {
Error ("Redefinition of function '%s' as different kind of symbol", Entry->Name);
Entry = 0;
}
} else if (E_SCType == SC_TYPEDEF) {
if (SCType == SC_TYPEDEF) {
/* New typedef must be identical */
if (TypeCmp (E_Type, T) < TC_EQUAL) {
Error ("Conflicting types for typedef '%s'", Entry->Name);
Entry = 0;
}
} else {
Error ("Redefinition of typedef '%s' as different kind of symbol", Entry->Name);
Entry = 0;
}
} else {
/* New type must be identical */
if (SCType != E_SCType) {
Error ("Redefinition of '%s' as different kind of symbol", Entry->Name);
Entry = 0;
} else if (TypeCmp (E_Type, T) < TC_EQUAL) {
Error ("Conflicting types for '%s'", Entry->Name);
Entry = 0;
} else if (E_SCType == SC_ENUMERATOR) {
/* Current code logic won't reach here, but still... */
Error ("Redeclaration of enumerator constant '%s'", Entry->Name);
Entry = 0;
}
}
}
/* Return if there are any errors */
return Entry == 0;
}
static void AddSymEntry (SymTable* T, SymEntry* S)
/* Add a symbol to a symbol table */
{
@ -554,28 +662,39 @@ static void AddSymEntry (SymTable* T, SymEntry* S)
SymEntry* AddEnumSym (const char* Name, const Type* Type, SymTable* Tab)
/* Add an enum entry and return it */
{
SymTable* CurTagTab = TagTab;
/* Do we have an entry with this name already? */
SymEntry* Entry = FindSymInTable (TagTab, Name, HashStr (Name));
SymEntry* Entry = FindSymInTable (CurTagTab, Name, HashStr (Name));
if (Entry) {
/* We do have an entry. This may be a forward, so check it. */
if ((Entry->Flags & SC_TYPEMASK) != SC_ENUM) {
/* Existing symbol is not an enum */
Error ("Symbol '%s' is already different kind", Name);
Entry = 0;
} else {
/* Define the struct size if the underlying type is given. */
if (Type != 0) {
if (Type !=0 && Entry->V.E.Type != 0) {
/* Both are definitions. */
Error ("Multiple definition for enum '%s'", Name);
Entry = 0;
} else {
Entry->Type = 0;
Entry->V.E.SymTab = Tab;
Entry->V.E.Type = Type;
}
Entry->Type = 0;
Entry->V.E.SymTab = Tab;
Entry->V.E.Type = Type;
}
}
} else {
if (Entry == 0) {
/* Use the fail-safe table for fictitious symbols */
CurTagTab = FailSafeTab;
}
}
if (Entry == 0) {
/* Create a new entry */
Entry = NewSymEntry (Name, SC_ENUM);
@ -586,7 +705,7 @@ SymEntry* AddEnumSym (const char* Name, const Type* Type, SymTable* Tab)
Entry->V.E.Type = Type;
/* Add it to the current table */
AddSymEntry (TagTab, Entry);
AddSymEntry (CurTagTab, Entry);
}
/* Return the entry */
@ -598,22 +717,25 @@ SymEntry* AddEnumSym (const char* Name, const Type* Type, SymTable* Tab)
SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable* Tab)
/* Add a struct/union entry and return it */
{
SymTable* CurTagTab = TagTab;
SymEntry* Entry;
/* Type must be struct or union */
PRECONDITION (Type == SC_STRUCT || Type == SC_UNION);
/* Do we have an entry with this name already? */
Entry = FindSymInTable (TagTab, Name, HashStr (Name));
Entry = FindSymInTable (CurTagTab, Name, HashStr (Name));
if (Entry) {
/* We do have an entry. This may be a forward, so check it. */
if ((Entry->Flags & SC_TYPEMASK) != Type) {
/* Existing symbol is not a struct */
Error ("Symbol '%s' is already different kind", Name);
Entry = 0;
} else if (Size > 0 && Entry->V.S.Size > 0) {
/* Both structs are definitions. */
Error ("Multiple definition for '%s'", Name);
Entry = 0;
} else {
/* Define the struct size if it is given */
if (Size > 0) {
@ -622,7 +744,13 @@ SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable
}
}
} else {
if (Entry == 0) {
/* Use the fail-safe table for fictitious symbols */
CurTagTab = FailSafeTab;
}
}
if (Entry == 0) {
/* Create a new entry */
Entry = NewSymEntry (Name, Type);
@ -631,8 +759,8 @@ SymEntry* AddStructSym (const char* Name, unsigned Type, unsigned Size, SymTable
Entry->V.S.SymTab = Tab;
Entry->V.S.Size = Size;
/* Add it to the current table */
AddSymEntry (TagTab, Entry);
/* Add it to the current tag table */
AddSymEntry (CurTagTab, Entry);
}
/* Return the entry */
@ -704,6 +832,7 @@ SymEntry* AddConstSym (const char* Name, const Type* T, unsigned Flags, long Val
}
DefOrRef* AddDefOrRef (SymEntry* E, unsigned Flags)
/* Add definition or reference to the SymEntry and preserve its attributes */
{
@ -721,6 +850,8 @@ DefOrRef* AddDefOrRef (SymEntry* E, unsigned Flags)
return DOR;
}
unsigned short FindSPAdjustment (const char* Name)
/* Search for an entry in the table of SP adjustments */
{
@ -733,6 +864,8 @@ unsigned short FindSPAdjustment (const char* Name)
return Entry->V.SPAdjustment;
}
SymEntry* AddLabelSym (const char* Name, unsigned Flags)
/* Add a goto label to the label table */
{
@ -848,15 +981,21 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs)
/* Add a local symbol and return the symbol entry */
{
SymTable* Tab = SymTab;
/* Do we have an entry with this name already? */
SymEntry* Entry = FindSymInTable (SymTab, Name, HashStr (Name));
SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
if (Entry) {
/* We have a symbol with this name already */
Error ("Multiple definition for '%s'", Name);
} else {
if (HandleSymRedefinition (Entry, T, Flags)) {
/* Use the fail-safe table for fictitious symbols */
Tab = FailSafeTab;
Entry = 0;
}
}
if (Entry == 0) {
/* Create a new entry */
Entry = NewSymEntry (Name, Flags);
@ -881,7 +1020,7 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
}
/* Add the entry to the symbol table */
AddSymEntry (SymTab, Entry);
AddSymEntry (Tab, Entry);
}
@ -898,101 +1037,46 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
int IsFunc = IsTypeFunc (T);
/* Functions must be inserted in the global symbol table */
SymTable* Tab = IsFunc? SymTab0 : SymTab;
SymTable* Tab = IsFunc ? SymTab0 : SymTab;
/* Do we have an entry with this name already? */
SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
if (Entry) {
Type* EType;
/* If the existing symbol is an enumerated constant,
** then avoid a compiler crash. See GitHub issue #728.
*/
if (Entry->Flags & SC_ENUMERATOR) {
Fatal ("Can't redeclare enumerator constant '%s' as global variable", Name);
}
/* We have a symbol with this name already */
if (Entry->Flags & SC_TYPEMASK) {
Error ("Multiple definition for '%s'", Name);
return Entry;
}
/* Get the type string of the existing symbol */
EType = Entry->Type;
/* If we are handling arrays, the old entry or the new entry may be an
** incomplete declaration. Accept this, and if the exsting entry is
** incomplete, complete it.
*/
if (IsTypeArray (T) && IsTypeArray (EType)) {
/* Get the array sizes */
long Size = GetElementCount (T);
long ESize = GetElementCount (EType);
if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
TypeCmp (T + 1, EType + 1) < TC_EQUAL) {
/* Types not identical: Conflicting types */
Error ("Conflicting types for '%s'", Name);
return Entry;
} else {
/* Check if we have a size in the existing definition */
if (ESize == UNSPECIFIED) {
/* Existing, size not given, use size from new def */
SetElementCount (EType, Size);
}
}
if (HandleSymRedefinition (Entry, T, Flags)) {
/* Use the fail-safe table for fictitious symbols */
Tab = FailSafeTab;
Entry = 0;
} else {
/* New type must be identical */
if (TypeCmp (EType, T) < TC_EQUAL) {
Error ("Conflicting types for '%s'", Name);
return Entry;
}
/* In case of a function, use the new type descriptor, since it
** contains pointers to the new symbol tables that are needed if
** an actual function definition follows. Be sure not to use the
** new descriptor if it contains a function declaration with an
** empty parameter list.
/* If a static declaration follows a non-static declaration, then
** warn about the conflict. (It will compile a public declaration.)
*/
if (IsFunc) {
/* Get the function descriptor from the new type */
FuncDesc* F = GetFuncDesc (T);
/* Use this new function descriptor if it doesn't contain
** an empty parameter list.
*/
if ((F->Flags & FD_EMPTY) == 0) {
Entry->V.F.Func = F;
SetFuncDesc (EType, F);
}
if ((Flags & SC_EXTERN) == 0 && (Entry->Flags & SC_EXTERN) != 0) {
Warning ("static declaration follows non-static declaration of '%s'.", Name);
}
/* An extern declaration must not change the current linkage. */
if (IsFunc || (Flags & (SC_EXTERN | SC_STORAGE)) == SC_EXTERN) {
Flags &= ~SC_EXTERN;
}
/* If a public declaration follows a static declaration, then
** warn about the conflict. (It will compile a public declaration.)
*/
if ((Flags & SC_EXTERN) != 0 && (Entry->Flags & SC_EXTERN) == 0) {
Warning ("public declaration follows static declaration of '%s'.", Name);
}
/* Add the new flags */
Entry->Flags |= Flags;
}
/* If a static declaration follows a non-static declaration, then
** warn about the conflict. (It will compile a public declaration.)
*/
if ((Flags & SC_EXTERN) == 0 && (Entry->Flags & SC_EXTERN) != 0) {
Warning ("static declaration follows non-static declaration of '%s'.", Name);
}
/* An extern declaration must not change the current linkage. */
if (IsFunc || (Flags & (SC_EXTERN | SC_STORAGE)) == SC_EXTERN) {
Flags &= ~SC_EXTERN;
}
/* If a public declaration follows a static declaration, then
** warn about the conflict. (It will compile a public declaration.)
*/
if ((Flags & SC_EXTERN) != 0 && (Entry->Flags & SC_EXTERN) == 0) {
Warning ("public declaration follows static declaration of '%s'.", Name);
}
/* Add the new flags */
Entry->Flags |= Flags;
} else {
}
if (Entry == 0) {
/* Create a new entry */
Entry = NewSymEntry (Name, Flags);