Hi rsmith,
OpenCL disallows various types (bool, size_t, pointers, or structs containing
them) to be used for kernel arguments, but currently they are accepted. The
error message in the struct case is currently a bit awkward since it doesn't
describe which struct member is at fault for not allowing the kernel argument.
http://llvm-reviews.chandlerc.com/D1052
Files:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
test/SemaOpenCL/invalid-kernel-arguments.cl
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6423,8 +6423,10 @@
"bitfields are not supported in OpenCL">;
def err_opencl_vla : Error<
"variable length arrays are not supported in OpenCL">;
-def err_event_t_kernel_arg : Error<
- "the event_t type cannot be used to declare a kernel function argument">;
+def err_bad_kernel_arg_type : Error<
+ "%0 cannot be used to declare a kernel function argument">;
+def err_struct_with_pointers_kernel_arg : Error<
+ "struct or union kernel arguments may not contain OpenCL objects">;
def err_event_t_global_var : Error<
"the event_t type cannot be used to declare a program scope variable">;
def err_event_t_struct_field : Error<
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1433,6 +1433,8 @@
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
void ActOnStartFunctionDeclarator();
void ActOnEndFunctionDeclarator();
+
+ void checkIsValidOpenCLKernelArgument(Declarator &D, ParmVarDecl *P);
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TypeSourceInfo *TInfo,
LookupResult &Previous,
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -5914,6 +5914,101 @@
}
}
+static bool isValidOpenCLKernelArgumentType(QualType PT) {
+ // OpenCL v1.2 s6.9.k:
+ // Arguments to kernel functions in a program cannot be declared with the
+ // built-in scalar types bool, half, size_t, ptrdiff_t, intptr_t, and
+ // uintptr_t or a struct and/or union that contain fields declared to be
+ // one of these built-in scalar types.
+ if (PT->isIntegerType()) {
+ if (PT->isBooleanType())
+ return false;
+
+ if (const TypedefType *Typedef = dyn_cast<TypedefType>(PT)) {
+ const IdentifierInfo *Identifier = Typedef->getDecl()->getIdentifier();
+ StringRef Name = Identifier->getName();
+
+ if (Name == "size_t" ||
+ Name == "ptrdiff_t" ||
+ Name == "intptr_t" ||
+ Name == "uintptr_t") {
+ return false;
+ }
+ }
+ }
+
+ // OpenCL v1.2 s6.8 n:
+ // A kernel function argument cannot be declared
+ // of event_t type.
+ if (PT->isEventT())
+ return false;
+
+ if (PT->isHalfType())
+ return false;
+
+ return true;
+}
+
+static const RecordType *getAsStructOrUnionType(QualType QT) {
+ const RecordType *RT = QT->getAsStructureType();
+ if (!RT)
+ RT = QT->getAsUnionType();
+
+ return RT;
+}
+
+void Sema::checkIsValidOpenCLKernelArgument(Declarator &D, ParmVarDecl *Param) {
+ QualType PT = Param->getType();
+
+ // OpenCL v1.2 s6.9.a:
+ // A kernel function argument cannot be declared as a
+ // pointer to a pointer type.
+ if (PT->isPointerType() && PT->getPointeeType()->isPointerType()) {
+ Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_arg);
+ D.setInvalidType();
+ }
+
+ if (!isValidOpenCLKernelArgumentType(PT)) {
+ Diag(Param->getLocation(), diag::err_bad_kernel_arg_type) << PT;
+ D.setInvalidType();
+ }
+
+ // OpenCL v1.2 s6.9.p:
+ // Arguments to kernel functions that are declared to be a struct or union
+ // do not allow OpenCL objects to be passed as elements of the struct or
+ // union.
+ SmallVector<const RecordType *, 4> NestedStructQueue;
+ const RecordType *RT = getAsStructOrUnionType(PT);
+ if (RT)
+ NestedStructQueue.push_back(RT);
+
+ while (!NestedStructQueue.empty()) {
+ RT = NestedStructQueue.pop_back_val();
+
+ const RecordDecl *RD = RT->getDecl();
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I) {
+ const FieldDecl *FD = *I;
+
+ QualType QT = FD->getType();
+ if (QT->isPointerType() || QT->isImageType()) {
+ Diag(Param->getLocation(), diag::err_struct_with_pointers_kernel_arg);
+ D.setInvalidType();
+ }
+
+ if (!isValidOpenCLKernelArgumentType(QT)) {
+ // TODO: A more specific warning about which struct members forbid this
+ // would be useful
+ Diag(Param->getLocation(), diag::err_bad_kernel_arg_type) << PT;
+ D.setInvalidType();
+ }
+
+ if (const RecordType *InnerRecord = getAsStructOrUnionType(QT))
+ NestedStructQueue.push_back(InnerRecord);
+ }
+ }
+}
+
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -6651,34 +6746,18 @@
Diag(D.getIdentifierLoc(), diag::err_static_kernel);
D.setInvalidType();
}
-
+
// OpenCL v1.2, s6.9 -- Kernels can only have return type void.
if (!NewFD->getResultType()->isVoidType()) {
Diag(D.getIdentifierLoc(),
diag::err_expected_kernel_void_return_type);
D.setInvalidType();
}
-
+
for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
PE = NewFD->param_end(); PI != PE; ++PI) {
ParmVarDecl *Param = *PI;
- QualType PT = Param->getType();
-
- // OpenCL v1.2 s6.9.a:
- // A kernel function argument cannot be declared as a
- // pointer to a pointer type.
- if (PT->isPointerType() && PT->getPointeeType()->isPointerType()) {
- Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_arg);
- D.setInvalidType();
- }
-
- // OpenCL v1.2 s6.8 n:
- // A kernel function argument cannot be declared
- // of event_t type.
- if (PT->isEventT()) {
- Diag(Param->getLocation(), diag::err_event_t_kernel_arg);
- D.setInvalidType();
- }
+ checkIsValidOpenCLKernelArgument(D, Param);
}
}
Index: test/SemaOpenCL/invalid-kernel-arguments.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCL/invalid-kernel-arguments.cl
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+
+// Disallowed: arguments with type
+// bool, half, size_t, ptrdiff_t, intptr_t, and uintptr_t
+// or a struct / union with any of these types in them
+
+
+// These would normally come from a header with the OpenCL builtins
+typedef unsigned int size_t;
+typedef size_t ptrdiff_t;
+typedef size_t intptr_t;
+typedef size_t uintptr_t;
+
+
+kernel void bool_arg(bool x) // expected-error{{'bool' cannot be used to declare a kernel function argument}}
+{
+
+}
+
+kernel void half_arg(half x) // expected-error{{'half' cannot be used to declare a kernel function argument}}
+{
+
+}
+
+kernel void size_t_arg(size_t x) // expected-error{{'size_t' (aka 'unsigned int') cannot be used to declare a kernel function argument}}
+{
+
+}
+
+kernel void ptrdiff_t_arg(ptrdiff_t x) // expected-error{{ptrdiff_t' (aka 'unsigned int') cannot be used to declare a kernel function argument}}
+{
+
+}
+
+
+kernel void intptr_t_arg(intptr_t x) // expected-error{{'intptr_t' (aka 'unsigned int') cannot be used to declare a kernel function argument}}
+{
+
+}
+
+kernel void uintptr_t_arg(uintptr_t x) // expected-error{{uintptr_t' (aka 'unsigned int') cannot be used to declare a kernel function argument}}
+{
+
+}
+
+typedef struct ContainsBool
+{
+ bool x;
+} ContainsBool;
+
+kernel void bool_in_struct_arg(ContainsBool x) // expected-error{{'ContainsBool' (aka 'struct ContainsBool') cannot be used to declare a kernel function argument}}
+{
+
+}
+
+
+
+typedef struct FooImage2D
+{
+ image2d_t* ptrField;
+} FooImage2D;
+
+kernel void image_in_struct_arg(FooImage2D arg) // expected-error{{struct or union kernel arguments may not contain OpenCL object}}
+{
+
+}
+
+
+typedef struct Foo
+{
+ int* ptrField;
+} Foo;
+
+kernel void pointer_in_struct_arg(Foo arg) // expected-error{{struct or union kernel arguments may not contain OpenCL object}}
+{
+
+}
+
+typedef union FooUnion
+{
+ int* ptrField;
+} FooUnion;
+
+kernel void pointer_in_union_arg(FooUnion arg) // expected-error{{struct or union kernel arguments may not contain OpenCL object}}
+{
+
+}
+
+typedef struct NestedPointer
+{
+ int x;
+ struct InnerNestedPointer
+ {
+ int* ptrField;
+ } inner;
+} NestedPointer;
+
+kernel void pointer_in_nested_struct_arg(NestedPointer arg) // expected-error{{struct or union kernel arguments may not contain OpenCL objects}}
+{
+
+}
+
+typedef struct NestedBool
+{
+ int x;
+ struct InnerNestedBool
+ {
+ bool boolField;
+ } inner;
+} NestedBool;
+
+kernel void bool_in_nested_struct_arg(NestedBool arg) // expected-error{{'NestedBool' (aka 'struct NestedBool') cannot be used to declare a kernel function argument}}
+{
+
+}
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits