Fixed function parameter checking.
Fixed function return type checking.
This commit is contained in:
@@ -410,8 +410,10 @@ fncls_t GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
(AutoCDecl ?
|
||||
IsQualFastcall (E->Type) :
|
||||
!IsQualCDecl (E->Type))) {
|
||||
/* Will use registers depending on the last param. */
|
||||
switch (CheckedSizeOf (D->LastParam->Type)) {
|
||||
/* Will use registers depending on the last param. If the last
|
||||
** param has incomplete type, just assume __EAX__.
|
||||
*/
|
||||
switch (SizeOf (D->LastParam->Type)) {
|
||||
case 1u:
|
||||
*Use = REG_A;
|
||||
break;
|
||||
|
||||
@@ -1704,7 +1704,6 @@ static void ParseAnsiParamList (FuncDesc* F)
|
||||
static FuncDesc* ParseFuncDecl (void)
|
||||
/* Parse the argument list of a function. */
|
||||
{
|
||||
unsigned Offs;
|
||||
SymEntry* Sym;
|
||||
SymEntry* WrappedCall;
|
||||
unsigned char WrappedCallData;
|
||||
@@ -1751,22 +1750,9 @@ static FuncDesc* ParseFuncDecl (void)
|
||||
*/
|
||||
F->LastParam = GetSymTab()->SymTail;
|
||||
|
||||
/* Assign offsets. If the function has a variable parameter list,
|
||||
** there's one additional byte (the arg size).
|
||||
/* It is allowed to use incomplete types in function prototypes, so we
|
||||
** won't always get to know the parameter sizes here and may do that later.
|
||||
*/
|
||||
Offs = (F->Flags & FD_VARIADIC)? 1 : 0;
|
||||
Sym = F->LastParam;
|
||||
while (Sym) {
|
||||
unsigned Size = CheckedSizeOf (Sym->Type);
|
||||
if (SymIsRegVar (Sym)) {
|
||||
Sym->V.R.SaveOffs = Offs;
|
||||
} else {
|
||||
Sym->V.Offs = Offs;
|
||||
}
|
||||
Offs += Size;
|
||||
F->ParamSize += Size;
|
||||
Sym = Sym->PrevSym;
|
||||
}
|
||||
|
||||
/* Leave the lexical level remembering the symbol tables */
|
||||
RememberFunctionLevel (F);
|
||||
|
||||
@@ -346,6 +346,9 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall)
|
||||
int FrameOffs = 0; /* Offset into parameter frame */
|
||||
int Ellipsis = 0; /* Function is variadic */
|
||||
|
||||
/* Make sure the size of all parameters are known */
|
||||
int ParamComplete = F_CheckParamList (Func, 1);
|
||||
|
||||
/* As an optimization, we may allocate the complete parameter frame at
|
||||
** once instead of pushing into each parameter as it comes. We may do that,
|
||||
** if...
|
||||
@@ -359,7 +362,7 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall)
|
||||
** (instead of pushing) is enabled.
|
||||
**
|
||||
*/
|
||||
if (IS_Get (&CodeSizeFactor) >= 200) {
|
||||
if (ParamComplete && IS_Get (&CodeSizeFactor) >= 200) {
|
||||
|
||||
/* Calculate the number and size of the parameters */
|
||||
FrameParams = Func->ParamCount;
|
||||
@@ -424,8 +427,10 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall)
|
||||
/* Evaluate the argument expression */
|
||||
hie1 (&Expr);
|
||||
|
||||
/* If we don't have a prototype, accept anything; otherwise, convert
|
||||
** the actual argument to the parameter type needed.
|
||||
/* Skip to the next parameter if there are any incomplete types */
|
||||
if (ParamComplete) {
|
||||
/* If we don't have an argument spec., accept anything; otherwise,
|
||||
** convert the actual argument to the type needed.
|
||||
*/
|
||||
Flags = CF_NONE;
|
||||
if (!Ellipsis) {
|
||||
@@ -484,6 +489,7 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall)
|
||||
/* Calculate total parameter size */
|
||||
PushedSize += ArgSize;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for end of argument list */
|
||||
if (CurTok.Tok != TOK_COMMA) {
|
||||
|
||||
@@ -105,6 +105,62 @@ static void FreeFunction (Function* F)
|
||||
|
||||
|
||||
|
||||
int F_CheckParamList (FuncDesc* D, int RequireAll)
|
||||
/* Check and set the parameter sizes.
|
||||
** If RequireAll is true, emit errors on parameters of incomplete types.
|
||||
** Return true if all parameters have complete types.
|
||||
*/
|
||||
{
|
||||
unsigned I = 0;
|
||||
unsigned Offs;
|
||||
SymEntry* Param;
|
||||
unsigned ParamSize = 0;
|
||||
unsigned IncompleteCount = 0;
|
||||
|
||||
/* Assign offsets. If the function has a variable parameter list,
|
||||
** there's one additional byte (the arg size).
|
||||
*/
|
||||
Offs = (D->Flags & FD_VARIADIC) ? 1 : 0;
|
||||
Param = D->LastParam;
|
||||
while (Param) {
|
||||
unsigned Size = SizeOf (Param->Type);
|
||||
if (RequireAll && IsIncompleteESUType (Param->Type)) {
|
||||
if (D->Flags & FD_UNNAMED_PARAMS) {
|
||||
Error ("Parameter %u has incomplete type '%s'",
|
||||
D->ParamCount - I,
|
||||
GetFullTypeName (Param->Type));
|
||||
} else {
|
||||
Error ("Parameter '%s' has incomplete type '%s'",
|
||||
Param->Name,
|
||||
GetFullTypeName (Param->Type));
|
||||
}
|
||||
++IncompleteCount;
|
||||
}
|
||||
if (SymIsRegVar (Param)) {
|
||||
Param->V.R.SaveOffs = Offs;
|
||||
} else {
|
||||
Param->V.Offs = Offs;
|
||||
}
|
||||
Offs += Size;
|
||||
ParamSize += Size;
|
||||
Param = Param->PrevSym;
|
||||
++I;
|
||||
}
|
||||
|
||||
/* If all parameters have complete types, set the total size description
|
||||
** and return true.
|
||||
*/
|
||||
if (IncompleteCount == 0) {
|
||||
D->ParamSize = ParamSize;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Otherwise return false */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* F_GetFuncName (const Function* F)
|
||||
/* Return the name of the current function */
|
||||
{
|
||||
@@ -378,9 +434,11 @@ static void F_EmitDebugInfo (void)
|
||||
void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* Parse argument declarations and function body. */
|
||||
{
|
||||
int ParamComplete; /* If all paramemters have complete types */
|
||||
int C99MainFunc = 0;/* Flag for C99 main function returning int */
|
||||
SymEntry* Param;
|
||||
const Type* RType; /* Real type used for struct parameters */
|
||||
const Type* ReturnType; /* Return type */
|
||||
|
||||
/* Remember this function descriptor used for definition */
|
||||
GetFuncDesc (Func->Type)->FuncDef = D;
|
||||
@@ -391,6 +449,21 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* Reenter the lexical level */
|
||||
ReenterFunctionLevel (D);
|
||||
|
||||
/* Check return type */
|
||||
ReturnType = F_GetReturnType (CurrentFunc);
|
||||
if (IsIncompleteESUType (ReturnType)) {
|
||||
/* There are already diagnostics on returning arrays or functions */
|
||||
if (!IsTypeArray (ReturnType) && !IsTypeFunc (ReturnType)) {
|
||||
Error ("Function has incomplete return type '%s'",
|
||||
GetFullTypeName (ReturnType));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check and set the parameter sizes. All parameter must have complete
|
||||
** types now.
|
||||
*/
|
||||
ParamComplete = F_CheckParamList (D, 1);
|
||||
|
||||
/* Check if the function header contains unnamed parameters. These are
|
||||
** only allowed in cc65 mode.
|
||||
*/
|
||||
@@ -429,7 +502,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* If cc65 extensions aren't enabled, don't allow a main function that
|
||||
** doesn't return an int.
|
||||
*/
|
||||
if (IS_Get (&Standard) != STD_CC65 && CurrentFunc->ReturnType[0].C != T_INT) {
|
||||
if (IS_Get (&Standard) != STD_CC65 && ReturnType[0].C != T_INT) {
|
||||
Error ("'main' must always return an int");
|
||||
}
|
||||
|
||||
@@ -472,17 +545,12 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
unsigned Flags;
|
||||
|
||||
/* Generate the push */
|
||||
if (IsTypeFunc (D->LastParam->Type)) {
|
||||
/* Pointer to function */
|
||||
Flags = CF_PTR;
|
||||
} else {
|
||||
/* Handle struct/union specially */
|
||||
if (IsClassStruct (D->LastParam->Type)) {
|
||||
Flags = TypeOf (GetStructReplacementType (D->LastParam->Type)) | CF_FORCECHAR;
|
||||
} else {
|
||||
Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR;
|
||||
}
|
||||
}
|
||||
g_push (Flags, 0);
|
||||
}
|
||||
|
||||
@@ -497,6 +565,8 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* Setup the stack */
|
||||
StackPtr = 0;
|
||||
|
||||
/* Emit code to handle the parameters if all of them have complete types */
|
||||
if (ParamComplete) {
|
||||
/* Walk through the parameter list and allocate register variable space
|
||||
** for parameters declared as register. Generate code to swap the contents
|
||||
** of the register bank with the save area on the stack.
|
||||
@@ -517,7 +587,6 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check for a register variable */
|
||||
if (SymIsRegVar (Param)) {
|
||||
|
||||
@@ -540,6 +609,7 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
|
||||
/* Next parameter */
|
||||
Param = Param->NextSym;
|
||||
}
|
||||
}
|
||||
|
||||
/* Need a starting curly brace */
|
||||
ConsumeLCurly ();
|
||||
|
||||
@@ -81,6 +81,12 @@ extern Function* CurrentFunc;
|
||||
|
||||
|
||||
|
||||
int F_CheckParamList (FuncDesc* D, int RequireAll);
|
||||
/* Check and set the parameter sizes.
|
||||
** If RequireAll is true, emit errors on parameters of incomplete types.
|
||||
** Return true if all parameters have complete types.
|
||||
*/
|
||||
|
||||
const char* F_GetFuncName (const Function* F);
|
||||
/* Return the name of the current function */
|
||||
|
||||
|
||||
@@ -318,15 +318,24 @@ static void ReturnStatement (void)
|
||||
/* Evaluate the return expression */
|
||||
hie0 (&Expr);
|
||||
|
||||
/* If we return something in a void function, print an error and
|
||||
** ignore the value. Otherwise convert the value to the type of the
|
||||
** return.
|
||||
/* If we return something in a function with void or incomplete return
|
||||
** type, print an error and ignore the value. Otherwise convert the
|
||||
** value to the type of the return.
|
||||
*/
|
||||
if (F_HasVoidReturn (CurrentFunc)) {
|
||||
Error ("Returning a value in function with return type void");
|
||||
Error ("Returning a value in function with return type 'void'");
|
||||
} else {
|
||||
|
||||
/* Check the return type first */
|
||||
ReturnType = F_GetReturnType (CurrentFunc);
|
||||
if (IsIncompleteESUType (ReturnType)) {
|
||||
/* Avoid excess errors */
|
||||
if (ErrorCount == 0) {
|
||||
Error ("Returning a value in function with incomplete return type");
|
||||
}
|
||||
} else {
|
||||
/* Convert the return value to the type of the function result */
|
||||
TypeConversion (&Expr, F_GetReturnType (CurrentFunc));
|
||||
TypeConversion (&Expr, ReturnType);
|
||||
|
||||
/* Load the value into the primary */
|
||||
if (IsClassStruct (Expr.Type)) {
|
||||
@@ -342,6 +351,7 @@ static void ReturnStatement (void)
|
||||
LoadExpr (CF_NONE, &Expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!F_HasVoidReturn (CurrentFunc) && !F_HasOldStyleIntRet (CurrentFunc)) {
|
||||
Error ("Function '%s' must return a value", F_GetFuncName (CurrentFunc));
|
||||
|
||||
Reference in New Issue
Block a user