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:
Matt Pharr
2011-12-14 12:22:49 -08:00
parent 89a5248f4f
commit 07f218137a
4 changed files with 92 additions and 23 deletions

View File

@@ -2705,19 +2705,21 @@ FunctionCallExpr::TypeCheck() {
launchCountExpr = launchCountExpr->TypeCheck();
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);
if (fse != 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]));
}
// 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<const PointerType *>(funcType) == NULL ||
dynamic_cast<const FunctionType *>(funcType->GetBaseType()) == NULL) {
assert(dynamic_cast<const PointerType *>(fptrType) != NULL);
const FunctionType *funcType =
dynamic_cast<const FunctionType *>(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<const FunctionType *>(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<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;
}
}
}

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

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

View 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.);
}