Actually typecheck the arguments to functions called through function pointers.
(Somehow this wasn't being done before.) Errors are now issued if too few arguments are used when calling through a function pointer, too many arguments are used, or if any of them can't be type converted to the parameter type.
This commit is contained in:
87
expr.cpp
87
expr.cpp
@@ -2705,19 +2705,21 @@ FunctionCallExpr::TypeCheck() {
|
|||||||
launchCountExpr = launchCountExpr->TypeCheck();
|
launchCountExpr = launchCountExpr->TypeCheck();
|
||||||
|
|
||||||
if (args != NULL && func != NULL) {
|
if (args != NULL && func != NULL) {
|
||||||
|
std::vector<const Type *> argTypes;
|
||||||
|
std::vector<bool> 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<FunctionSymbolExpr *>(func);
|
FunctionSymbolExpr *fse = dynamic_cast<FunctionSymbolExpr *>(func);
|
||||||
if (fse != NULL) {
|
if (fse != NULL) {
|
||||||
std::vector<const Type *> argTypes;
|
// Regular function call
|
||||||
std::vector<bool> 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]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fse->ResolveOverloads(args->pos, argTypes, &argCouldBeNULL) == false)
|
if (fse->ResolveOverloads(args->pos, argTypes, &argCouldBeNULL) == false)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -2756,25 +2758,66 @@ FunctionCallExpr::TypeCheck() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const Type *funcType = func->GetType();
|
// Call through a function pointer
|
||||||
if (funcType == NULL)
|
const Type *fptrType = func->GetType();
|
||||||
|
if (fptrType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (dynamic_cast<const PointerType *>(funcType) == NULL ||
|
assert(dynamic_cast<const PointerType *>(fptrType) != NULL);
|
||||||
dynamic_cast<const FunctionType *>(funcType->GetBaseType()) == NULL) {
|
const FunctionType *funcType =
|
||||||
|
dynamic_cast<const FunctionType *>(fptrType->GetBaseType());
|
||||||
|
if (funcType == NULL) {
|
||||||
Error(pos, "Must provide function name or function pointer for "
|
Error(pos, "Must provide function name or function pointer for "
|
||||||
"function call expression.");
|
"function call expression.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (funcType->IsVaryingType()) {
|
// Make sure we don't have too many arguments for the function
|
||||||
const FunctionType *ft =
|
if ((int)argTypes.size() > funcType->GetNumParameters()) {
|
||||||
dynamic_cast<const FunctionType *>(funcType->GetBaseType());
|
Error(args->pos, "Too many parameter values provided in "
|
||||||
if (ft->GetReturnType()->IsUniformType()) {
|
"function call (%d provided, %d expected).",
|
||||||
Error(pos, "Illegal to call a varying function pointer that "
|
(int)argTypes.size(), funcType->GetNumParameters());
|
||||||
"points to a function with a uniform return type.");
|
return NULL;
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<const PointerType *>(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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
tests_errors/fptr-typecheck-1.ispc
Normal file
9
tests_errors/fptr-typecheck-1.ispc
Normal file
@@ -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);
|
||||||
|
}
|
||||||
9
tests_errors/fptr-typecheck-2.ispc
Normal file
9
tests_errors/fptr-typecheck-2.ispc
Normal file
@@ -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);
|
||||||
|
}
|
||||||
8
tests_errors/fptr-typecheck-3.ispc
Normal file
8
tests_errors/fptr-typecheck-3.ispc
Normal file
@@ -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.);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user