[OpenCL] Reject block arguments
authorSven van Haastregt <sven.vanhaastregt@arm.com>
Mon, 29 Jun 2020 13:13:12 +0000 (14:13 +0100)
committerSven van Haastregt <sven.vanhaastregt@arm.com>
Mon, 29 Jun 2020 13:13:12 +0000 (14:13 +0100)
OpenCL 2.0 does not allow block arguments, primarily because it is
difficult to support function pointers on the various architectures
that OpenCL targets.  Clang was still accepting them.

Rename and reuse the `err_opencl_half_param` diagnostic.

Fixes PR46324.

Differential Revision: https://reviews.llvm.org/D82313

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaType.cpp
clang/test/CodeGenOpenCL/blocks.cl
clang/test/Frontend/opencl.cl
clang/test/SemaOpenCL/invalid-block.cl

index 70b43f5..f092133 100644 (file)
@@ -830,8 +830,8 @@ def err_opencl_half_load_store : Error<
 def err_opencl_cast_to_half : Error<"casting to type %0 is not allowed">;
 def err_opencl_half_declaration : Error<
   "declaring variable of type %0 is not allowed">;
-def err_opencl_half_param : Error<
-  "declaring function parameter of type %0 is not allowed; did you forget * ?">;
+def err_opencl_invalid_param : Error<
+  "declaring function parameter of type %0 is not allowed%select{; did you forget * ?|}1">;
 def err_opencl_invalid_return : Error<
   "declaring function return value of type %0 is not allowed %select{; did you forget * ?|}1">;
 def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
index 08d12fc..52fe292 100644 (file)
@@ -5139,8 +5139,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
             // FIXME: This really should be in BuildFunctionType.
             if (S.getLangOpts().OpenCL) {
               if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) {
-                S.Diag(Param->getLocation(),
-                  diag::err_opencl_half_param) << ParamTy;
+                S.Diag(Param->getLocation(), diag::err_opencl_invalid_param)
+                    << ParamTy << 0;
                 D.setInvalidType();
                 Param->setInvalidDecl();
               }
@@ -5159,6 +5159,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
                 Param->setKNRPromoted(true);
               }
             }
+          } else if (S.getLangOpts().OpenCL && ParamTy->isBlockPointerType()) {
+            // OpenCL 2.0 s6.12.5: A block cannot be a parameter of a function.
+            S.Diag(Param->getLocation(), diag::err_opencl_invalid_param)
+                << ParamTy << 1 /*hint off*/;
+            D.setInvalidType();
           }
 
           if (LangOpts.ObjCAutoRefCount && Param->hasAttr<NSConsumedAttr>()) {
index c3e2685..f831551 100644 (file)
@@ -70,26 +70,6 @@ void foo(){
 
 // COMMON-NOT: define{{.*}}@__foo_block_invoke_kernel
 
-// Test that we support block arguments.
-// COMMON-LABEL: define {{.*}} @blockArgFunc
-int blockArgFunc(int (^ bl)(void)) {
-  return bl();
-}
-
-// COMMON-LABEL: define {{.*}} @get21
-// COMMON: define {{.*}} @__get21_block_invoke
-// COMMON: ret i32 21
-int get21() {
-  return blockArgFunc(^{return 21;});
-}
-
-// COMMON-LABEL: define {{.*}} @get42
-// COMMON: define {{.*}} @__get42_block_invoke
-// COMMON: ret i32 42
-int get42() {
-  return blockArgFunc(^{return 42;});
-}
-
 // COMMON-LABEL: define {{.*}}@call_block
 // call {{.*}}@__call_block_block_invoke
 int call_block() {
index ea7d3d4..e25a4b8 100644 (file)
@@ -21,7 +21,7 @@ int member;
 #endif
 #endif
 
-void f(void (^g)(void)) {
+typedef int (^bl_t)(void);
 #if defined(__OPENCL_C_VERSION__) || defined(__OPENCL_CPP_VERSION__)
 #if !defined(BLOCKS) && (defined(__OPENCL_CPP_VERSION__)  || __OPENCL_C_VERSION__ != CL_VERSION_2_0)
   // expected-error@-3{{blocks support disabled - compile with -fblocks or for OpenCL 2.0}}
@@ -29,7 +29,6 @@ void f(void (^g)(void)) {
 #else
   // expected-error@-6{{blocks support disabled - compile with -fblocks or pick a deployment target that supports them}}
 #endif
-}
 
 // CHECK-INVALID-OPENCL-VERSION11: warning: OpenCL version 1.1 does not support the option '-cl-strict-aliasing'
 // CHECK-INVALID-OPENCL-VERSION12: warning: OpenCL version 1.2 does not support the option '-cl-strict-aliasing'
index ec74d16..0fb2e26 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -verify -fblocks -cl-std=CL2.0 %s
 
 // OpenCL v2.0 s6.12.5
-void f0(int (^const bl)());
+void f0(int (^const bl)()); // expected-error{{declaring function parameter of type 'int (__generic ^const __private)(void)' is not allowed}}
 // All blocks declarations must be const qualified and initialized.
 void f1() {
   int (^bl1)(void) = ^() {
@@ -26,9 +26,18 @@ void f2() {
   };
 }
 
-// A block cannot be the return value of a function.
+// A block cannot be the return value or parameter of a function.
 typedef int (^bl_t)(void);
-bl_t f3(bl_t bl); // expected-error{{declaring function return value of type 'bl_t' (aka 'int (__generic ^const)(void)') is not allowed}}
+bl_t f3a(int);     // expected-error{{declaring function return value of type 'bl_t' (aka 'int (__generic ^const)(void)') is not allowed}}
+bl_t f3b(bl_t bl);
+// expected-error@-1{{declaring function return value of type 'bl_t' (aka 'int (__generic ^const)(void)') is not allowed}}
+// expected-error@-2{{declaring function parameter of type '__private bl_t' (aka 'int (__generic ^const __private)(void)') is not allowed}}
+void f3c() {
+  // Block with a block argument.
+  int (^const bl2)(bl_t block_arg) = ^() { // expected-error{{declaring function parameter of type '__private bl_t' (aka 'int (__generic ^const __private)(void)') is not allowed}}
+    return block_arg(); // expected-error{{implicit declaration of function 'block_arg' is invalid in OpenCL}}
+  };
+}
 
 struct bl_s {
   int (^bl)(void); // expected-error {{the 'int (__generic ^const)(void)' type cannot be used to declare a structure or union field}}