Merge pull request #2248 from acqn/ReturnTypeCheck

[cc65] Improved function return type check
This commit is contained in:
Bob Andrews
2023-11-01 15:08:48 +01:00
committed by GitHub
3 changed files with 83 additions and 76 deletions

View File

@@ -493,8 +493,44 @@ static void FixQualifiers (Type* DataType)
static void FixFunctionReturnType (Type* T)
/* Check if the data type consists of any functions returning forbidden return
** types and remove qualifiers from the return types if they are not void.
*/
{
while (T->C != T_END) {
if (IsTypeFunc (T)) {
++T;
/* Functions may not return functions or arrays */
if (IsTypeFunc (T)) {
Error ("Functions are not allowed to return functions");
} else if (IsTypeArray (T)) {
Error ("Functions are not allowed to return arrays");
}
/* The return type must not be qualified */
if ((GetQualifier (T) & T_QUAL_CVR) != T_QUAL_NONE) {
/* We are stricter than the standard here */
if (GetRawTypeRank (T) == T_RANK_VOID) {
/* A qualified void type is always an error */
Error ("Function definition has qualified void return type");
} else {
/* For others, qualifiers are ignored */
Warning ("Type qualifiers ignored on function return type");
T[0].C &= ~T_QUAL_CVR;
}
}
} else {
++T;
}
}
}
static void CheckArrayElementType (const Type* T) static void CheckArrayElementType (const Type* T)
/* Check if data type consists of arrays of incomplete element types */ /* Check recursively if type consists of arrays of forbidden element types */
{ {
while (T->C != T_END) { while (T->C != T_END) {
if (IsTypeArray (T)) { if (IsTypeArray (T)) {
@@ -2061,46 +2097,39 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
/* Do several fixes on qualifiers */ /* Do several fixes on qualifiers */
FixQualifiers (D->Type); FixQualifiers (D->Type);
/* Check if the data type consists of any arrays of forbidden types */ /* Check if the data type consists of any functions returning forbidden return
CheckArrayElementType (D->Type); ** types and remove qualifiers from the return types if they are not void.
*/
FixFunctionReturnType (D->Type);
/* If we have a function, add a special storage class */ /* Check recursively if the data type consists of arrays of forbidden types */
if (IsTypeFunc (D->Type)) { CheckArrayElementType (D->Type);
D->StorageClass |= SC_FUNC;
}
/* Parse attributes for this declarator */ /* Parse attributes for this declarator */
ParseAttribute (D); ParseAttribute (D);
/* Check several things for function or function pointer types */ /* If we have a function, add a special storage class */
if (IsTypeFunc (D->Type) || IsTypeFuncPtr (D->Type)) { if (IsTypeFunc (D->Type)) {
/* A function. Check the return type */ D->StorageClass |= SC_FUNC;
Type* RetType = GetFuncReturnTypeModifiable (D->Type);
/* Functions may not return functions or arrays */ } else if (!IsTypeVoid (D->Type)) {
if (IsTypeFunc (RetType)) { /* Check the size of the generated type */
Error ("Functions are not allowed to return functions"); unsigned Size = SizeOf (D->Type);
} else if (IsTypeArray (RetType)) {
Error ("Functions are not allowed to return arrays");
}
/* The return type must not be qualified */ if (Size >= 0x10000) {
if (GetQualifier (RetType) != T_QUAL_NONE && RetType[1].C == T_END) { if (D->Ident[0] != '\0') {
Error ("Size of '%s' is invalid (0x%06X)", D->Ident, Size);
if (GetRawTypeRank (RetType) == T_RANK_VOID) {
/* A qualified void type is always an error */
Error ("function definition has qualified void return type");
} else { } else {
/* For others, qualifiers are ignored */ Error ("Invalid size in declaration (0x%06X)", Size);
Warning ("type qualifiers ignored on function return type"); }
RetType[0].C = GetUnqualRawTypeCode (RetType);
} }
} }
/* Warn about an implicit int return in the function */ /* Check a few pre-C99 things */
if ((Spec->Flags & DS_DEF_TYPE) != 0 && if ((Spec->Flags & DS_DEF_TYPE) != 0) {
RetType[0].C == T_INT && RetType[1].C == T_END) { /* Check and warn about an implicit int return in the function */
if (IsTypeFunc (D->Type) && IsRankInt (GetFuncReturnType (D->Type))) {
/* Function has an implicit int return. Output a warning if we don't /* Function has an implicit int return. Output a warning if we don't
** have the C89 standard enabled explicitly. ** have the C89 standard enabled explicitly.
*/ */
@@ -2110,8 +2139,6 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET; GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
} }
}
/* For anthing that is not a function or typedef, check for an implicit /* For anthing that is not a function or typedef, check for an implicit
** int declaration. ** int declaration.
*/ */
@@ -2120,21 +2147,10 @@ void ParseDecl (const DeclSpec* Spec, Declarator* D, declmode_t Mode)
/* If the standard was not set explicitly to C89, print a warning /* If the standard was not set explicitly to C89, print a warning
** for variables with implicit int type. ** for variables with implicit int type.
*/ */
if ((Spec->Flags & DS_DEF_TYPE) != 0 && IS_Get (&Standard) >= STD_C99) { if (IS_Get (&Standard) >= STD_C99) {
Warning ("Implicit 'int' is an obsolete feature"); Warning ("Implicit 'int' is an obsolete feature");
} }
} }
if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type)) {
/* Check the size of the generated type */
unsigned Size = SizeOf (D->Type);
if (Size >= 0x10000) {
if (D->Ident[0] != '\0') {
Error ("Size of '%s' is invalid (0x%06X)", D->Ident, Size);
} else {
Error ("Invalid size in declaration (0x%06X)", Size);
}
}
} }
if (PrevErrorCount != ErrorCount) { if (PrevErrorCount != ErrorCount) {

View File

@@ -466,11 +466,15 @@ void NewFunc (SymEntry* Func, FuncDesc* D)
/* Check return type */ /* Check return type */
ReturnType = F_GetReturnType (CurrentFunc); ReturnType = F_GetReturnType (CurrentFunc);
if (IsIncompleteESUType (ReturnType)) {
/* There are already diagnostics on returning arrays or functions */
if (!IsTypeArray (ReturnType) && !IsTypeFunc (ReturnType)) { if (!IsTypeArray (ReturnType) && !IsTypeFunc (ReturnType)) {
/* There are already diagnostics on returning arrays or functions */
if (IsIncompleteESUType (ReturnType)) {
Error ("Function has incomplete return type '%s'", Error ("Function has incomplete return type '%s'",
GetFullTypeName (ReturnType)); GetFullTypeName (ReturnType));
} else if (IsPassByRefType (ReturnType)) {
/* Handle struct/union specially */
Error ("Function return type '%s' of size %u is unsupported",
GetFullTypeName (ReturnType), SizeOf (ReturnType));
} }
} }

View File

@@ -311,7 +311,6 @@ static void ReturnStatement (void)
/* Handle the 'return' statement */ /* Handle the 'return' statement */
{ {
ExprDesc Expr; ExprDesc Expr;
const Type* ReturnType;
ED_Init (&Expr); ED_Init (&Expr);
NextToken (); NextToken ();
@@ -327,32 +326,20 @@ static void ReturnStatement (void)
if (F_HasVoidReturn (CurrentFunc)) { 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 { } else {
/* Check the return type first */ /* Check the return type first */
ReturnType = F_GetReturnType (CurrentFunc); const Type* 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 */ /* Convert the return value to the type of the function result */
TypeConversion (&Expr, ReturnType); TypeConversion (&Expr, ReturnType);
/* Load the value into the primary */ /* Load the value into the primary */
if (IsClassStruct (Expr.Type)) { if (IsClassStruct (Expr.Type)) {
/* Handle struct/union specially */ /* Handle struct/union specially */
ReturnType = GetStructReplacementType (Expr.Type); LoadExpr (CG_TypeOf (GetStructReplacementType (ReturnType)), &Expr);
if (ReturnType == Expr.Type) {
Error ("Returning '%s' of this size by value is not supported", GetFullTypeName (Expr.Type));
}
LoadExpr (CG_TypeOf (ReturnType), &Expr);
} else { } else {
/* Load the value into the primary */ /* Load the value into the primary */
LoadExpr (CF_NONE, &Expr); LoadExpr (CF_NONE, &Expr);
} }
}
/* Append deferred inc/dec at sequence point */ /* Append deferred inc/dec at sequence point */
DoDeferred (SQP_KEEP_EAX, &Expr); DoDeferred (SQP_KEEP_EAX, &Expr);