diff --git a/expr.cpp b/expr.cpp index 47981be2..577f61a7 100644 --- a/expr.cpp +++ b/expr.cpp @@ -2705,19 +2705,21 @@ FunctionCallExpr::TypeCheck() { launchCountExpr = launchCountExpr->TypeCheck(); if (args != NULL && func != NULL) { + std::vector argTypes; + std::vector argCouldBeNULL; + for (unsigned int i = 0; i < args->exprs.size(); ++i) { + if (args->exprs[i] == NULL) + return NULL; + const Type *t = args->exprs[i]->GetType(); + if (t == NULL) + return NULL; + argTypes.push_back(t); + argCouldBeNULL.push_back(lIsAllIntZeros(args->exprs[i])); + } + FunctionSymbolExpr *fse = dynamic_cast(func); if (fse != NULL) { - std::vector argTypes; - std::vector argCouldBeNULL; - for (unsigned int i = 0; i < args->exprs.size(); ++i) { - if (args->exprs[i] == NULL) - return NULL; - const Type *t = args->exprs[i]->GetType(); - if (t == NULL) - return NULL; - argTypes.push_back(t); - argCouldBeNULL.push_back(lIsAllIntZeros(args->exprs[i])); - } + // Regular function call if (fse->ResolveOverloads(args->pos, argTypes, &argCouldBeNULL) == false) return NULL; @@ -2756,25 +2758,66 @@ FunctionCallExpr::TypeCheck() { } } else { - const Type *funcType = func->GetType(); - if (funcType == NULL) + // Call through a function pointer + const Type *fptrType = func->GetType(); + if (fptrType == NULL) return NULL; - - if (dynamic_cast(funcType) == NULL || - dynamic_cast(funcType->GetBaseType()) == NULL) { + + assert(dynamic_cast(fptrType) != NULL); + const FunctionType *funcType = + dynamic_cast(fptrType->GetBaseType()); + if (funcType == NULL) { Error(pos, "Must provide function name or function pointer for " "function call expression."); return NULL; } + + // Make sure we don't have too many arguments for the function + if ((int)argTypes.size() > funcType->GetNumParameters()) { + Error(args->pos, "Too many parameter values provided in " + "function call (%d provided, %d expected).", + (int)argTypes.size(), funcType->GetNumParameters()); + return NULL; + } + // It's ok to have too few arguments, as long as the function's + // default parameter values have started by the time we run out + // of arguments + if ((int)argTypes.size() < funcType->GetNumParameters() && + funcType->GetParameterDefault(argTypes.size()) == NULL) { + Error(args->pos, "Too few parameter values provided in " + "function call (%d provided, %d expected).", + (int)argTypes.size(), funcType->GetNumParameters()); + return NULL; + } - if (funcType->IsVaryingType()) { - const FunctionType *ft = - dynamic_cast(funcType->GetBaseType()); - if (ft->GetReturnType()->IsUniformType()) { - Error(pos, "Illegal to call a varying function pointer that " - "points to a function with a uniform return type."); - return NULL; + // Now make sure they can all type convert to the corresponding + // parameter types.. + for (int i = 0; i < (int)argTypes.size(); ++i) { + if (i < funcType->GetNumParameters()) { + // make sure it can type convert + const Type *paramType = funcType->GetParameterType(i); + if (CanConvertTypes(argTypes[i], paramType) == false && + !(argCouldBeNULL[i] == true && + dynamic_cast(paramType) != NULL)) { + Error(args->exprs[i]->pos, "Can't convert argument of " + "type \"%s\" to type \"%s\" for funcion call " + "argument.", argTypes[i]->GetString().c_str(), + paramType->GetString().c_str()); + return NULL; + } } + else + // Otherwise the parameter default saves us. It should + // be there for sure, given the check right above the + // for loop. + assert(funcType->GetParameterDefault(i) != NULL); + } + + if (fptrType->IsVaryingType() && + funcType->GetReturnType()->IsUniformType()) { + Error(pos, "Illegal to call a varying function pointer that " + "points to a function with a uniform return type."); + return NULL; } } } diff --git a/tests_errors/fptr-typecheck-1.ispc b/tests_errors/fptr-typecheck-1.ispc new file mode 100644 index 00000000..1c04269d --- /dev/null +++ b/tests_errors/fptr-typecheck-1.ispc @@ -0,0 +1,9 @@ +// Too many parameter values provided in function call + +float bar(float a, float b); + +export uniform int foo(uniform int x[], uniform int i[]) { + float (*fptr)(float, float) = bar; +//CO bar(0,1,2); + fptr(0., 1, 2); +} diff --git a/tests_errors/fptr-typecheck-2.ispc b/tests_errors/fptr-typecheck-2.ispc new file mode 100644 index 00000000..13071fcd --- /dev/null +++ b/tests_errors/fptr-typecheck-2.ispc @@ -0,0 +1,9 @@ +// Can't convert argument of type "void * const uniform" to type "float" for funcion call argument. + +float bar(float a, float b); + +export uniform int foo(uniform int x[], uniform int i[]) { + float (*fptr)(float, float) = bar; +//CO bar(0,1,2); + fptr(NULL, 1); +} diff --git a/tests_errors/fptr-typecheck-3.ispc b/tests_errors/fptr-typecheck-3.ispc new file mode 100644 index 00000000..26412632 --- /dev/null +++ b/tests_errors/fptr-typecheck-3.ispc @@ -0,0 +1,8 @@ +// Too few parameter values provided in function call (1 provided, 2 expected). + +float bar(float a, float b); + +export uniform int foo(uniform int x[], uniform int i[]) { + float (*fptr)(float, float) = bar; + fptr(1.); +}