Anastasia created this revision.
Anastasia added a reviewer: yaxunl.
Anastasia added a subscriber: cfe-commits.

OpenCL disallows using variadic arguments (s6.9.e and s6.12.5 OpenCL v2.0) 
apart from some exceptions:

- printf
- enqueue_kernel

This change adds error diagnostic for variadic functions but accepts printf and 
any compiler internal function (which should cover __enqueue_kernel_XXX cases). 
It also unifies diagnostic with block prototype and adds missing uncaught cases 
for blocks.

Note that this implementation checks against printf name. Alternative approach 
would be to enable printf as Clang builtin and diagnose using custom Sema 
checks. Though it 's not clear whether this brings any  benefit.


https://reviews.llvm.org/D25935

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaType.cpp
  test/SemaOpenCL/builtin.cl
  test/SemaOpenCL/func.cl
  test/SemaOpenCL/func_ptr.cl
  test/SemaOpenCL/invalid-block.cl

Index: test/SemaOpenCL/invalid-block.cl
===================================================================
--- test/SemaOpenCL/invalid-block.cl
+++ test/SemaOpenCL/invalid-block.cl
@@ -31,23 +31,30 @@
 }
 
 // A block with variadic argument is not allowed.
-int (^bl)(int, ...) = ^int(int I, ...) { // expected-error {{invalid block prototype, variadic arguments are not allowed in OpenCL}}
+int (^bl)(int, ...) = ^int(int I, ...) { // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}} expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
   return 0;
 };
+typedef int (^bl1_t)(int, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
 
 // A block can't be used to declare an array
-typedef int (^bl1_t)(int);
+typedef int (^bl2_t)(int);
 void f5(int i) {
-  bl1_t bl1 = ^(int i) {return 1;};
-  bl1_t bl2 = ^(int i) {return 2;};
-  bl1_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl1_t' (aka 'int (^const)(int)') type is invalid in OpenCL}}
+  bl2_t bl1 = ^(int i) {
+    return 1;
+  };
+  bl2_t bl2 = ^(int i) {
+    return 2;
+  };
+  bl2_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl2_t' (aka 'int (^const)(int)') type is invalid in OpenCL}}
   int tmp = i ? bl1(i)      // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}}
               : bl2(i);     // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}}
 }
 // A block pointer type and all pointer operations are disallowed
-void f6(bl1_t * bl_ptr) { // expected-error{{pointer to type '__generic bl1_t' (aka 'int (^const __generic)(int)') is invalid in OpenCL}}
-  bl1_t bl = ^(int i) {return 1;};
-  bl1_t *p; // expected-error {{pointer to type '__generic bl1_t' (aka 'int (^const __generic)(int)') is invalid in OpenCL}}
-  *bl;  // expected-error {{invalid argument type 'bl1_t' (aka 'int (^const)(int)') to unary expression}}
-  &bl; // expected-error {{invalid argument type 'bl1_t' (aka 'int (^const)(int)') to unary expression}}
+void f6(bl2_t *bl_ptr) { // expected-error{{pointer to type '__generic bl2_t' (aka 'int (^const __generic)(int)') is invalid in OpenCL}}
+  bl2_t bl = ^(int i) {
+    return 1;
+  };
+  bl2_t *p; // expected-error {{pointer to type '__generic bl2_t' (aka 'int (^const __generic)(int)') is invalid in OpenCL}}
+  *bl;      // expected-error {{invalid argument type 'bl2_t' (aka 'int (^const)(int)') to unary expression}}
+  &bl;      // expected-error {{invalid argument type 'bl2_t' (aka 'int (^const)(int)') to unary expression}}
 }
Index: test/SemaOpenCL/func_ptr.cl
===================================================================
--- test/SemaOpenCL/func_ptr.cl
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
-
-void foo(void*);
-
-void bar()
-{
-  // declaring a function pointer is an error
-  void (*fptr)(int); // expected-error{{pointers to functions are not allowed}}
-
-  // taking the address of a function is an error
-  foo((void*)foo); // expected-error{{taking address of function is not allowed}}
-  foo(&foo); // expected-error{{taking address of function is not allowed}}
-
-  // initializing an array with the address of functions is an error
-  void* vptrarr[2] = {foo, &foo}; // expected-error{{taking address of function is not allowed}} expected-error{{taking address of function is not allowed}}
-
-  // just calling a function is correct
-  foo(0);
-}
Index: test/SemaOpenCL/func.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCL/func.cl
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+// Variadic functions
+void vararg_f(int, ...);                    // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
+void __vararg_f(int, ...);
+typedef void (*vararg_fptr_t)(int, ...);    // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
+int printf(__constant const char *st, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
+
+//Function pointer
+void foo(void*);
+
+void bar()
+{
+  // declaring a function pointer is an error
+  void (*fptr)(int); // expected-error{{pointers to functions are not allowed}}
+
+  // taking the address of a function is an error
+  foo((void*)foo); // expected-error{{taking address of function is not allowed}}
+  foo(&foo); // expected-error{{taking address of function is not allowed}}
+
+  // initializing an array with the address of functions is an error
+  void* vptrarr[2] = {foo, &foo}; // expected-error{{taking address of function is not allowed}} expected-error{{taking address of function is not allowed}}
+
+  // just calling a function is correct
+  foo(0);
+}
Index: test/SemaOpenCL/builtin.cl
===================================================================
--- test/SemaOpenCL/builtin.cl
+++ test/SemaOpenCL/builtin.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL1.2
 
 // expected-no-diagnostics
 
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -4043,13 +4043,26 @@
         }
       }
 
+      if (LangOpts.OpenCL) {
         // OpenCL v2.0 s6.12.5 - A block cannot be the return value of a
         // function.
-      if (LangOpts.OpenCL && (T->isBlockPointerType() || T->isImageType() ||
-                              T->isSamplerT() || T->isPipeType())) {
-        S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
-            << T << 1 /*hint off*/;
-        D.setInvalidType(true);
+        if (T->isBlockPointerType() || T->isImageType() || T->isSamplerT() ||
+            T->isPipeType()) {
+          S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
+              << T << 1 /*hint off*/;
+          D.setInvalidType(true);
+        }
+        // OpenCL doesn't support variadic functions and blocks
+        // (s6.9.e and s6.12.5 OpenCL v2.0) except for printf.
+        // We also allow here any toolchain reserved identifiers.
+        if (FTI.isVariadic &&
+            !(D.getIdentifier() &&
+              ((D.getIdentifier()->getName() == "printf" &&
+                LangOpts.OpenCLVersion >= 120) ||
+               D.getIdentifier()->getName().startswith("__")))) {
+          S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function);
+          D.setInvalidType(true);
+        }
       }
 
       // Methods cannot return interface types. All ObjC objects are
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -6861,17 +6861,6 @@
         NewVD->setInvalidDecl();
         return;
       }
-      // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not supported.
-      // TODO: this check is not enough as it doesn't diagnose the typedef
-      const BlockPointerType *BlkTy = T->getAs<BlockPointerType>();
-      const FunctionProtoType *FTy =
-          BlkTy->getPointeeType()->getAs<FunctionProtoType>();
-      if (FTy && FTy->isVariadic()) {
-        Diag(NewVD->getLocation(), diag::err_opencl_block_proto_variadic)
-            << T << NewVD->getSourceRange();
-        NewVD->setInvalidDecl();
-        return;
-      }
     }
     // OpenCL v1.2 s6.5 - All program scope variables must be declared in the
     // __constant address space.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7993,8 +7993,6 @@
   " in the declaration statement in the program scope">;
 def err_opencl_implicit_vector_conversion : Error<
   "implicit conversions between vector types (%0 and %1) are not permitted">;
-def err_opencl_block_proto_variadic : Error<
-  "invalid block prototype, variadic arguments are not allowed in OpenCL">;
 def err_opencl_invalid_type_array : Error<
   "array of %0 type is invalid in OpenCL">;
 def err_opencl_ternary_with_block : Error<
@@ -8006,6 +8004,8 @@
 def warn_opencl_attr_deprecated_ignored : Warning <
   "%0 attribute is deprecated and ignored in OpenCL version %1">,
   InGroup<IgnoredAttributes>;
+def err_opencl_variadic_function : Error<
+  "invalid prototype, variadic arguments are not allowed in OpenCL">;
 
 // OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions
 def err_opencl_builtin_pipe_first_arg : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to