1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 07:29:33 +00:00

Fixed compatibility checking of function declarations by using the composite types of them.

This commit is contained in:
acqn 2020-08-12 21:35:47 +08:00 committed by Oliver Schmidt
parent 44d52935da
commit 13ed557b92
10 changed files with 129 additions and 88 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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).

View File

@ -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).

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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 {

View File

@ -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;

View File

@ -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 */