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

Reply via email to