Partially address review comments. Remove Sema member, rename argument to 
parameter, combine parameter check function, and use 
diag::note_member_declared_here on structs with invalid types in them. Does not 
yet show the chain of fields that are problematic, just the lowest one. Also 
update event_t test for changed warning.

Hi rsmith,

http://llvm-reviews.chandlerc.com/D1052

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D1052?vs=2588&id=2727#toc

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaDecl.cpp
  test/SemaOpenCL/event_t.cl
  test/SemaOpenCL/invalid-kernel-parameters.cl
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6423,16 +6423,18 @@
   "invalid reinterpretation: sizes of %0 and %1 must match">;
 def err_static_kernel : Error<
   "kernel functions cannot be declared static">;
-def err_opencl_ptrptr_kernel_arg : Error<
-  "kernel argument cannot be declared as a pointer to a pointer">;
+def err_opencl_ptrptr_kernel_param : Error<
+  "kernel parameter cannot be declared as a pointer to a pointer">;
 def err_static_function_scope : Error<
   "variables in function scope cannot be declared static">;
 def err_opencl_bitfields : Error<
   "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_param_type : Error<
+  "%0 cannot be used to declare a kernel function parameter">;
+def err_struct_with_pointers_kernel_param : Error<
+  "struct or union kernel parameters 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
@@ -1446,6 +1446,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
@@ -6042,6 +6042,143 @@
   }
 }
 
+enum OpenCLParamType {
+  ValidKernelParam,
+  PtrPtrKernelParam,
+  BoolKernelParam,
+  IntTypeKernelParam,
+  EventKernelParam,
+  HalfKernelParam,
+  PtrKernelParam,
+  RecordKernelParam
+};
+
+static OpenCLParamType getOpenCLKernelParameterType(QualType PT) {
+  if (PT->isPointerType()) {
+    QualType PointeeType = PT->getPointeeType();
+    return PointeeType->isPointerType() ? PtrPtrKernelParam : PtrKernelParam;
+  }
+
+  if (PT->isImageType())
+    return PtrKernelParam;
+
+  if (PT->isIntegerType()) {
+    if (PT->isBooleanType())
+      return BoolKernelParam;
+
+    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 IntTypeKernelParam;
+      }
+    }
+  }
+
+  if (PT->isEventT())
+    return EventKernelParam;
+
+  if (PT->isHalfType())
+    return HalfKernelParam;
+
+  if (PT->isRecordType())
+    return RecordKernelParam;
+
+  return ValidKernelParam;
+}
+
+static void checkIsValidOpenCLKernelParameter(Sema &S,
+                                              Declarator &D,
+                                              ParmVarDecl *Param) {
+  QualType PT = Param->getType();
+
+  switch (getOpenCLKernelParameterType(PT)) {
+  case PtrPtrKernelParam:
+    // OpenCL v1.2 s6.9.a:
+    // A kernel function argument cannot be declared as a
+    // pointer to a pointer type.
+    S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param);
+    D.setInvalidType();
+    return;
+
+  case BoolKernelParam:
+  case HalfKernelParam:
+  case IntTypeKernelParam:
+    // 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.
+
+  case EventKernelParam:
+    // OpenCL v1.2 s6.8 n:
+    // A kernel function argument cannot be declared
+    // of event_t type.
+    S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
+    D.setInvalidType();
+    return;
+
+  case PtrKernelParam:
+  case ValidKernelParam:
+    return;
+
+  case RecordKernelParam:
+    break;
+  }
+
+  const RecordType *RT = PT->getAs<RecordType>();
+  assert(RT && "Should only have RecordType arguments at this point");
+
+  SmallVector<const RecordType *, 4> NestedStructQueue;
+  NestedStructQueue.push_back(RT);
+
+  while (!NestedStructQueue.empty()) {
+    const RecordType *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();
+      switch (getOpenCLKernelParameterType(QT)) {
+      case ValidKernelParam:
+        break;
+
+      case PtrKernelParam:
+      case PtrPtrKernelParam:
+        // 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.
+        S.Diag(Param->getLocation(),
+               diag::err_struct_with_pointers_kernel_param);
+        S.Diag(FD->getLocation(), diag::note_member_declared_here)
+          << FD->getDeclName();
+        D.setInvalidType();
+        break;
+
+      case BoolKernelParam:
+      case HalfKernelParam:
+      case IntTypeKernelParam:
+      case EventKernelParam:
+        S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT;
+        S.Diag(FD->getLocation(), diag::note_member_declared_here)
+          << FD->getDeclName();
+        D.setInvalidType();
+        break;
+
+      case RecordKernelParam:
+        NestedStructQueue.push_back(QT->getAs<RecordType>());
+      }
+    }
+  }
+}
+
 NamedDecl*
 Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
                               TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -6777,34 +6914,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();
-      }
+      checkIsValidOpenCLKernelParameter(*this, D, Param);
     }
   }
 
Index: test/SemaOpenCL/event_t.cl
===================================================================
--- test/SemaOpenCL/event_t.cl
+++ test/SemaOpenCL/event_t.cl
@@ -8,7 +8,7 @@
 
 void foo(event_t evt); // expected-note {{passing argument to parameter 'evt' here}}
 
-void kernel ker(event_t argevt) { // expected-error {{the event_t type cannot be used to declare a kernel function argument}}
+void kernel ker(event_t argevt) { // expected-error {{'event_t' cannot be used to declare a kernel function parameter}}
   event_t e;
   constant event_t const_evt; // expected-error {{the event_t type can only be used with __private address space qualifier}}
   foo(e);
Index: test/SemaOpenCL/invalid-kernel-parameters.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCL/invalid-kernel-parameters.cl
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+
+// Disallowed: parameters 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 parameter}}
+
+kernel void half_arg(half x) { } // expected-error{{'half' cannot be used to declare a kernel function parameter}}
+
+kernel void size_t_arg(size_t x) { } // expected-error{{'size_t' (aka 'unsigned int') cannot be used to declare a kernel function parameter}}
+
+kernel void ptrdiff_t_arg(ptrdiff_t x) { } // expected-error{{ptrdiff_t' (aka 'unsigned int') cannot be used to declare a kernel function parameter}}
+
+kernel void intptr_t_arg(intptr_t x) { } // expected-error{{'intptr_t' (aka 'unsigned int') cannot be used to declare a kernel function parameter}}
+
+kernel void uintptr_t_arg(uintptr_t x) { } // expected-error{{uintptr_t' (aka 'unsigned int') cannot be used to declare a kernel function parameter}}
+
+typedef struct ContainsBool
+{
+  bool x; // expected-note{{member 'x' declared here}}
+} ContainsBool;
+
+kernel void bool_in_struct_arg(ContainsBool x) { } // expected-error{{'ContainsBool' (aka 'struct ContainsBool') cannot be used to declare a kernel function parameter}}
+
+
+
+typedef struct FooImage2D
+{
+  image2d_t imageField; // expected-note{{member 'imageField' declared here}}
+} FooImage2D;
+
+kernel void image_in_struct_arg(FooImage2D arg) { } // expected-error{{struct or union kernel parameters may not contain OpenCL object}}
+
+typedef struct Foo
+{
+  int* ptrField; // expected-note{{member 'ptrField' declared here}}
+} Foo;
+
+kernel void pointer_in_struct_arg(Foo arg) { } // expected-error{{struct or union kernel parameters may not contain OpenCL object}}
+
+typedef union FooUnion
+{
+  int* ptrField; // expected-note{{member 'ptrField' declared here}}
+} FooUnion;
+
+kernel void pointer_in_union_arg(FooUnion arg) { }// expected-error{{struct or union kernel parameters may not contain OpenCL object}}
+
+typedef struct NestedPointer
+{
+  int x;
+  struct InnerNestedPointer
+  {
+    int* ptrField; // expected-note{{member 'ptrField' declared here}}
+  } inner;
+} NestedPointer;
+
+kernel void pointer_in_nested_struct_arg(NestedPointer arg) { }// expected-error{{struct or union kernel parameters may not contain OpenCL objects}}
+
+typedef struct NestedBool
+{
+  int x;
+  struct InnerNestedBool
+  {
+    bool boolField; // expected-note{{member 'boolField' declared here}}
+  } 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 parameter}}
+
+
+// Check for note with a struct not defined inside the struct
+typedef struct NestedBool2Inner
+{
+  bool boolField; // expected-note{{member 'boolField' declared here}}
+} NestedBool2Inner;
+
+typedef struct NestedBool2
+{
+  int x;
+  NestedBool2Inner inner;
+} NestedBool2;
+
+kernel void bool_in_nested_struct_2_arg(NestedBool2 arg) { } // expected-error{{'NestedBool2' (aka 'struct NestedBool2') cannot be used to declare a kernel function parameter}}
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to