mirror of
https://github.com/cc65/cc65.git
synced 2025-01-26 17:36:57 +00:00
Fixed compatibility checking of function declarations by using the composite types of them.
This commit is contained in:
parent
44d52935da
commit
13ed557b92
@ -392,7 +392,7 @@ fncls_t GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
|
||||
/* Did we find it in the top-level table? */
|
||||
if (E && IsTypeFunc (E->Type)) {
|
||||
FuncDesc* D = E->V.F.Func;
|
||||
FuncDesc* D = GetFuncCompositeDesc (E);
|
||||
|
||||
/* A variadic function will use the Y register (the parameter list
|
||||
** size is passed there). A fastcall function will use the A or A/X
|
||||
|
@ -177,18 +177,23 @@ static void Parse (void)
|
||||
}
|
||||
|
||||
/* If this is a function declarator that is not followed by a comma
|
||||
** or semicolon, it must be followed by a function body. If this is
|
||||
** the case, convert an empty parameter list into one accepting no
|
||||
** parameters (same as void) as required by the standard.
|
||||
** or semicolon, it must be followed by a function body.
|
||||
*/
|
||||
if ((Decl.StorageClass & SC_FUNC) != 0 &&
|
||||
(CurTok.Tok != TOK_COMMA) &&
|
||||
(CurTok.Tok != TOK_SEMI)) {
|
||||
if ((Decl.StorageClass & SC_FUNC) != 0) {
|
||||
if (CurTok.Tok != TOK_COMMA && CurTok.Tok != TOK_SEMI) {
|
||||
/* A definition */
|
||||
Decl.StorageClass |= SC_DEF;
|
||||
|
||||
FuncDesc* D = GetFuncDesc (Decl.Type);
|
||||
|
||||
if (D->Flags & FD_EMPTY) {
|
||||
D->Flags = (D->Flags & ~FD_EMPTY) | FD_VOID_PARAM;
|
||||
/* Convert an empty parameter list into one accepting no
|
||||
** parameters (same as void) as required by the standard.
|
||||
*/
|
||||
FuncDesc* D = GetFuncDesc (Decl.Type);
|
||||
if (D->Flags & FD_EMPTY) {
|
||||
D->Flags = (D->Flags & ~FD_EMPTY) | FD_VOID_PARAM;
|
||||
}
|
||||
} else {
|
||||
/* Just a declaration */
|
||||
Decl.StorageClass |= SC_DECL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,13 +314,6 @@ SkipOneDecl:
|
||||
/* Prototype only */
|
||||
NextToken ();
|
||||
} else {
|
||||
|
||||
/* Function body. Check for duplicate function definitions */
|
||||
if (SymIsDef (Entry)) {
|
||||
Error ("Body for function '%s' has already been defined",
|
||||
Entry->Name);
|
||||
}
|
||||
|
||||
/* Parse the function body */
|
||||
NewFunc (Entry);
|
||||
}
|
||||
|
@ -1115,6 +1115,28 @@ Type* GetFuncReturn (Type* T)
|
||||
|
||||
|
||||
|
||||
Type* GetFuncCompositeType (SymEntry* Func)
|
||||
/* Get the composite function type */
|
||||
{
|
||||
/* Be sure it's a function type */
|
||||
CHECK (IsClassFunc (Func->Type));
|
||||
|
||||
return Func->V.F.Composite->Type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FuncDesc* GetFuncCompositeDesc (SymEntry* Func)
|
||||
/* Get the composite function type descriptor */
|
||||
{
|
||||
/* Be sure it's a function type */
|
||||
CHECK (IsClassFunc (Func->Type));
|
||||
|
||||
return GetFuncDesc (Func->V.F.Composite->Type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
long GetElementCount (const Type* T)
|
||||
/* Get the element count of the array specified in T (which must be of
|
||||
** array type).
|
||||
|
@ -753,6 +753,12 @@ void SetFuncDesc (Type* T, FuncDesc* F);
|
||||
Type* GetFuncReturn (Type* T) attribute ((const));
|
||||
/* Return a pointer to the return type of a function or pointer-to-function type */
|
||||
|
||||
Type* GetFuncCompositeType (struct SymEntry* Func);
|
||||
/* Get the composite function type */
|
||||
|
||||
FuncDesc* GetFuncCompositeDesc (struct SymEntry* Func);
|
||||
/* Get the composite function type descriptor */
|
||||
|
||||
long GetElementCount (const Type* T);
|
||||
/* Get the element count of the array specified in T (which must be of
|
||||
** array type).
|
||||
|
@ -1749,7 +1749,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
||||
/* Was there a previous entry? If so, copy WrappedCall info from it */
|
||||
PrevEntry = FindGlobalSym (D->Ident);
|
||||
if (PrevEntry && PrevEntry->Flags & SC_FUNC) {
|
||||
FuncDesc* D = PrevEntry->V.F.Func;
|
||||
FuncDesc* D = GetFuncDesc (PrevEntry->Type);
|
||||
if (D->WrappedCall && !F->WrappedCall) {
|
||||
F->WrappedCall = D->WrappedCall;
|
||||
F->WrappedCallData = D->WrappedCallData;
|
||||
|
@ -295,7 +295,7 @@ static void F_RestoreRegVars (Function* F)
|
||||
}
|
||||
|
||||
/* Get the first symbol from the function symbol table */
|
||||
Sym = F->FuncEntry->V.F.Func->SymTab->SymHead;
|
||||
Sym = GetFuncDesc (F->FuncEntry->Type)->SymTab->SymHead;
|
||||
|
||||
/* Walk through all symbols checking for register variables */
|
||||
while (Sym) {
|
||||
@ -383,7 +383,7 @@ void NewFunc (SymEntry* Func)
|
||||
const Type* RType; /* Real type used for struct parameters */
|
||||
|
||||
/* Get the function descriptor from the function entry */
|
||||
FuncDesc* D = Func->V.F.Func;
|
||||
FuncDesc* D = GetFuncDesc (Func->Type);
|
||||
|
||||
/* Allocate the function activation record for the function */
|
||||
CurrentFunc = NewFunction (Func);
|
||||
|
@ -427,8 +427,8 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
||||
ParseDecl (Spec, &Decl, DM_NEED_IDENT);
|
||||
|
||||
/* Check if there are any non-extern storage classes set for function
|
||||
** declarations. The only valid storage class for function declarations
|
||||
** inside functions is 'extern'.
|
||||
** declarations. Function can only be declared inside functions with the
|
||||
** 'extern' storage class specifier or no storage class specifier at all.
|
||||
*/
|
||||
if ((Decl.StorageClass & SC_FUNC) == SC_FUNC) {
|
||||
|
||||
@ -439,12 +439,11 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
||||
Error ("Illegal storage class on function");
|
||||
}
|
||||
|
||||
/* The default storage class could be wrong. Just use 'extern' in all
|
||||
** cases.
|
||||
*/
|
||||
/* The default storage class could be wrong. Just clear them */
|
||||
Decl.StorageClass &= ~SC_STORAGEMASK;
|
||||
Decl.StorageClass |= SC_EXTERN;
|
||||
|
||||
/* This is always a declaration */
|
||||
Decl.StorageClass |= SC_DECL;
|
||||
}
|
||||
|
||||
/* If we don't have a name, this was flagged as an error earlier.
|
||||
@ -456,6 +455,7 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
||||
|
||||
/* If the symbol is not marked as external, it will be defined now */
|
||||
if ((Decl.StorageClass & SC_FICTITIOUS) == 0 &&
|
||||
(Decl.StorageClass & SC_DECL) == 0 &&
|
||||
(Decl.StorageClass & SC_EXTERN) == 0) {
|
||||
Decl.StorageClass |= SC_DEF;
|
||||
}
|
||||
@ -500,8 +500,14 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the symbol to the symbol table */
|
||||
AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, 0);
|
||||
if ((Decl.StorageClass & SC_EXTERN) == SC_EXTERN ||
|
||||
(Decl.StorageClass & SC_FUNC) == SC_FUNC) {
|
||||
/* Add the global symbol to the local symbol table */
|
||||
AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass);
|
||||
} else {
|
||||
/* Add the local symbol to the local symbol table */
|
||||
AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ static void WrappedCallPragma (StrBuf* B)
|
||||
|
||||
PushWrappedCall(Entry, (unsigned char) Val);
|
||||
Entry->Flags |= SC_REF;
|
||||
Entry->V.F.Func->Flags |= FD_CALL_WRAPPER;
|
||||
GetFuncCompositeDesc (Entry)->Flags |= FD_CALL_WRAPPER;
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -191,7 +191,7 @@ struct SymEntry {
|
||||
|
||||
/* Data for functions */
|
||||
struct {
|
||||
struct FuncDesc* Func; /* Function descriptor */
|
||||
SymEntry* Composite;/* Entry to hold composite function type */
|
||||
struct Segments* Seg; /* Segments for this function */
|
||||
struct LiteralPool* LitPool; /* Literal pool for this function */
|
||||
} F;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "anonname.h"
|
||||
#include "asmcode.h"
|
||||
#include "asmlabel.h"
|
||||
#include "codegen.h"
|
||||
@ -558,9 +559,10 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
unsigned E_SCType = Entry->Flags & SC_TYPEMASK;
|
||||
unsigned SCType = Flags & SC_TYPEMASK;
|
||||
|
||||
/* Existing typedefs cannot be redeclared as anything different */
|
||||
/* Some symbols may be redeclared if certain requirements are met */
|
||||
if (E_SCType == SC_TYPEDEF) {
|
||||
|
||||
/* Existing typedefs cannot be redeclared as anything different */
|
||||
if (SCType == SC_TYPEDEF) {
|
||||
if (TypeCmp (E_Type, T) < TC_IDENTICAL) {
|
||||
Error ("Conflicting types for typedef '%s'", Entry->Name);
|
||||
@ -571,9 +573,42 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
Entry = 0;
|
||||
}
|
||||
|
||||
} else 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)) {
|
||||
|
||||
/* Check for duplicate function definitions */
|
||||
if (SymIsDef (Entry) && (Flags & SC_DEF) == SC_DEF) {
|
||||
Error ("Body for function '%s' has already been defined",
|
||||
Entry->Name);
|
||||
Entry = 0;
|
||||
} else {
|
||||
/* New type must be compatible with the composite prototype */
|
||||
if (TypeCmp (GetFuncCompositeType (Entry), T) < TC_EQUAL) {
|
||||
Error ("Conflicting function types for '%s'", Entry->Name);
|
||||
Entry = 0;
|
||||
} else {
|
||||
/* Refine the existing composite prototype with this new
|
||||
** one.
|
||||
*/
|
||||
RefineFuncDesc (GetFuncCompositeType (Entry), T);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Error ("Redefinition of function '%s' as different kind of symbol", Entry->Name);
|
||||
Entry = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Some symbols may be redeclared if certain requirements are met */
|
||||
/* Redeclarations of ESU types are checked elsewhere */
|
||||
if (IsTypeArray (T) && IsTypeArray (E_Type)) {
|
||||
|
||||
/* Get the array sizes */
|
||||
@ -597,37 +632,6 @@ static int HandleSymRedefinition (SymEntry* Entry, const Type* T, unsigned Flags
|
||||
}
|
||||
}
|
||||
|
||||
} else 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 equivalent */
|
||||
if (TypeCmp (E_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 {
|
||||
|
||||
/* New type must be equivalent */
|
||||
@ -1067,7 +1071,8 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
||||
} else if ((Flags & SC_REGISTER) == SC_REGISTER) {
|
||||
Entry->V.R.RegOffs = Offs;
|
||||
Entry->V.R.SaveOffs = StackPtr;
|
||||
} else if ((Flags & SC_EXTERN) == SC_EXTERN) {
|
||||
} else if ((Flags & SC_EXTERN) == SC_EXTERN ||
|
||||
(Flags & SC_FUNC) == SC_FUNC) {
|
||||
Entry->V.L.Label = Offs;
|
||||
SymSetAsmName (Entry);
|
||||
} else if ((Flags & SC_STATIC) == SC_STATIC) {
|
||||
@ -1080,7 +1085,6 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
||||
|
||||
/* Add the entry to the symbol table */
|
||||
AddSymEntry (Tab, Entry);
|
||||
|
||||
}
|
||||
|
||||
/* Return the entry */
|
||||
@ -1092,16 +1096,12 @@ 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 */
|
||||
{
|
||||
/* There is some special handling for functions, so check if it is one */
|
||||
int IsFunc = IsTypeFunc (T);
|
||||
|
||||
/* Functions must be inserted in the global symbol table */
|
||||
SymTable* Tab = IsFunc ? SymTab0 : SymTab;
|
||||
/* Use the global symbol table */
|
||||
SymTable* Tab = SymTab;
|
||||
|
||||
/* Do we have an entry with this name already? */
|
||||
SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
|
||||
SymEntry* Entry = FindSymInTree (Tab, Name);
|
||||
if (Entry) {
|
||||
|
||||
/* We have a symbol with this name already */
|
||||
if (HandleSymRedefinition (Entry, T, Flags)) {
|
||||
/* Use the fail-safe table for fictitious symbols */
|
||||
@ -1111,31 +1111,34 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
} else {
|
||||
|
||||
/* If a static declaration follows a non-static declaration, then
|
||||
** warn about the conflict. (It will compile a public declaration.)
|
||||
** warn about the conflict. It will compile an extern 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 an extern declaration follows a static declaration, then
|
||||
** warn about the conflict. It will compile an extern declaration.
|
||||
*/
|
||||
if ((Flags & SC_EXTERN) != 0 && (Entry->Flags & SC_EXTERN) == 0) {
|
||||
Warning ("public declaration follows static declaration of '%s'.", Name);
|
||||
Warning ("extern declaration follows static declaration of '%s'.", Name);
|
||||
}
|
||||
|
||||
/* Update existing function type if this is a definition */
|
||||
if (IsTypeFunc (Entry->Type) &&
|
||||
!SymIsDef (Entry) &&
|
||||
(Flags & SC_DEF) == SC_DEF) {
|
||||
TypeFree (Entry->Type);
|
||||
Entry->Type = TypeDup (T);
|
||||
}
|
||||
|
||||
/* Add the new flags */
|
||||
Entry->Flags |= Flags;
|
||||
Entry->Flags |= Flags & ~SC_EXTERN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Entry == 0) {
|
||||
if (Entry == 0 || Entry->Owner != Tab) {
|
||||
|
||||
/* Create a new entry */
|
||||
Entry = NewSymEntry (Name, Flags);
|
||||
@ -1143,12 +1146,18 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
|
||||
/* Set the symbol attributes */
|
||||
Entry->Type = TypeDup (T);
|
||||
|
||||
/* If this is a function, set the function descriptor and clear
|
||||
/* If this is a function, set the function composite typeand clear
|
||||
** additional fields.
|
||||
*/
|
||||
if (IsFunc) {
|
||||
Entry->V.F.Func = GetFuncDesc (Entry->Type);
|
||||
Entry->V.F.Seg = 0;
|
||||
if (IsTypeFunc (T)) {
|
||||
/* GitHub #1167 - Make a composite prototype */
|
||||
ident Ident;
|
||||
AnonName (Ident, "prototype");
|
||||
Entry->V.F.Composite = NewSymEntry (Ident, SC_EXTERN | SC_DECL | SC_ALIAS | SC_FUNC);
|
||||
Entry->V.F.Composite->Type = TypeDup (T);
|
||||
AddSymEntry (SymTab0, Entry->V.F.Composite);
|
||||
|
||||
Entry->V.F.Seg = 0;
|
||||
}
|
||||
|
||||
/* Add the assembler name of the symbol */
|
||||
|
Loading…
x
Reference in New Issue
Block a user