r262616 - [OpenCL] Apply missing restrictions for Blocks in OpenCL v2.0

Anastasia Stulova via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 3 05:33:20 PST 2016


Author: stulova
Date: Thu Mar  3 07:33:19 2016
New Revision: 262616

URL: http://llvm.org/viewvc/llvm-project?rev=262616&view=rev
Log:
[OpenCL] Apply missing restrictions for Blocks in OpenCL v2.0

Applying the following restrictions for block types in OpenCL (v2.0 s6.12.5):
 - __block storage class is disallowed
 - every block declaration must be const qualified and initialized
 - a block can't be used as a return type of a function
 - a blocks can't be used to declare a structure or union field
 - extern speficier is disallowed

Corrected image and sampler types diagnostics with struct and unions.

Review: http://reviews.llvm.org/D16928


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CodeGen/blocks-opencl.cl
    cfe/trunk/test/SemaOpenCL/event_t.cl
    cfe/trunk/test/SemaOpenCL/invalid-block.cl
    cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl
    cfe/trunk/test/SemaOpenCL/sampler_t.cl

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Mar  3 07:33:19 2016
@@ -623,8 +623,8 @@ 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_half_return : Error<
-  "declaring function return value of type %0 is not allowed; did you forget * ?">;
+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">;
 def warn_pragma_options_align_reset_failed : Warning<
   "#pragma options align=reset failed: %0">,
@@ -7701,8 +7701,8 @@ def note_illegal_field_declared_here : N
   "field of illegal %select{type|pointer type}0 %1 declared here">;
 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<
-  "the event_t type cannot be used to declare a structure or union field">;
+def err_opencl_type_struct_or_union_field : Error<
+  "the %0 type cannot be used to declare a structure or union field">;
 def err_event_t_addr_space_qual : Error<
   "the event_t type can only be used with __private address space qualifier">;
 def err_expected_kernel_void_return_type : Error<
@@ -7764,6 +7764,14 @@ def err_opencl_multiple_access_qualifier
 def err_opencl_unknown_type_specifier : Error<
   "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">;
 
+// OpenCL v2.0 s6.12.5 Blocks restrictions
+def err_opencl_block_storage_type : Error<
+  "the __block storage type is not permitted">;
+def err_opencl_invalid_block_declaration : Error<
+  "invalid block variable declaration - must be %select{const qualified|initialized}0">;
+def err_opencl_extern_block_declaration : Error<
+  "invalid block variable declaration - using 'extern' storage class is disallowed">;
+
 } // end of sema category
 
 let CategoryName = "OpenMP Issue" in {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Mar  3 07:33:19 2016
@@ -6585,7 +6585,7 @@ void Sema::CheckVariableDeclarationType(
     return;
   }
 
-  // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program
+  // OpenCL v1.2 s6.8 - The static qualifier is valid only in program
   // scope.
   if (getLangOpts().OpenCLVersion == 120 &&
       !getOpenCLOptions().cl_clang_storage_class_specifiers &&
@@ -6595,12 +6595,44 @@ void Sema::CheckVariableDeclarationType(
     return;
   }
 
-  // OpenCL v1.2 s6.5 - All program scope variables must be declared in the
-  // __constant address space.
-  // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static
-  // variables inside a function can also be declared in the global
-  // address space.
   if (getLangOpts().OpenCL) {
+    // OpenCL v2.0 s6.12.5 - The __block storage type is not supported.
+    if (NewVD->hasAttr<BlocksAttr>()) {
+      Diag(NewVD->getLocation(), diag::err_opencl_block_storage_type);
+      return;
+    }
+
+    if (T->isBlockPointerType()) {
+      // OpenCL v2.0 s6.12.5 - Any block declaration must be const qualified and
+      // can't use 'extern' storage class.
+      if (!T.isConstQualified()) {
+        Diag(NewVD->getLocation(), diag::err_opencl_invalid_block_declaration)
+            << 0 /*const*/;
+        NewVD->setInvalidDecl();
+        return;
+      }
+      if (NewVD->hasExternalStorage()) {
+        Diag(NewVD->getLocation(), diag::err_opencl_extern_block_declaration);
+        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.
+    // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static
+    // variables inside a function can also be declared in the global
+    // address space.
     if (NewVD->isFileVarDecl()) {
       if (!T->isSamplerT() &&
           !(T.getAddressSpace() == LangAS::opencl_constant ||
@@ -6735,19 +6767,6 @@ void Sema::CheckVariableDeclarationType(
     NewVD->setInvalidDecl();
     return;
   }
-
-  // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not supported.
-  if (LangOpts.OpenCL && T->isBlockPointerType()) {
-    const BlockPointerType *BlkTy = T->getAs<BlockPointerType>();
-    const FunctionProtoType *FTy =
-        BlkTy->getPointeeType()->getAs<FunctionProtoType>();
-    if (FTy->isVariadic()) {
-      Diag(NewVD->getLocation(), diag::err_opencl_block_proto_variadic)
-          << T << NewVD->getSourceRange();
-      NewVD->setInvalidDecl();
-      return;
-    }
-  }
 }
 
 /// \brief Perform semantic checking on a newly-created variable
@@ -10058,6 +10077,18 @@ Sema::ActOnCXXForRangeIdentifier(Scope *
 void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
   if (var->isInvalidDecl()) return;
 
+  if (getLangOpts().OpenCL) {
+    // OpenCL v2.0 s6.12.5 - Every block variable declaration must have an
+    // initialiser
+    if (var->getTypeSourceInfo()->getType()->isBlockPointerType() &&
+        !var->hasInit()) {
+      Diag(var->getLocation(), diag::err_opencl_invalid_block_declaration)
+          << 1 /*Init*/;
+      var->setInvalidDecl();
+      return;
+    }
+  }
+
   // In Objective-C, don't allow jumps past the implicit initialization of a
   // local retaining variable.
   if (getLangOpts().ObjC1 &&
@@ -13110,10 +13141,11 @@ FieldDecl *Sema::HandleField(Scope *S, R
     D.setInvalidType();
   }
 
-  // OpenCL 1.2 spec, s6.9 r:
-  // The event type cannot be used to declare a structure or union field.
-  if (LangOpts.OpenCL && T->isEventT()) {
-    Diag(Loc, diag::err_event_t_struct_field);
+  // OpenCL v1.2 s6.9b,r & OpenCL v2.0 s6.12.5 - The following types cannot be
+  // used as structure or union field: image, sampler, event or block types.
+  if (LangOpts.OpenCL && (T->isEventT() || T->isImageType() ||
+                          T->isSamplerT() || T->isBlockPointerType())) {
+    Diag(Loc, diag::err_opencl_type_struct_or_union_field) << T;
     D.setInvalidType();
   }
 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Thu Mar  3 07:33:19 2016
@@ -3921,7 +3921,8 @@ static TypeSourceInfo *GetFullTypeForDec
       if (T->isHalfType()) {
         if (S.getLangOpts().OpenCL) {
           if (!S.getOpenCLOptions().cl_khr_fp16) {
-            S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T;
+            S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
+                << T << 0 /*pointer hint*/;
             D.setInvalidType(true);
           } 
         } else if (!S.getLangOpts().HalfArgsAndReturns) {
@@ -3931,6 +3932,14 @@ static TypeSourceInfo *GetFullTypeForDec
         }
       }
 
+        // OpenCL v2.0 s6.12.5 - A block cannot be the return value of a
+        // function.
+      if (LangOpts.OpenCL && T->isBlockPointerType()) {
+        S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
+            << T << 1 /*hint off*/;
+        D.setInvalidType(true);
+      }
+
       // Methods cannot return interface types. All ObjC objects are
       // passed by reference.
       if (T->isObjCObjectType()) {

Modified: cfe/trunk/test/CodeGen/blocks-opencl.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/blocks-opencl.cl?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/blocks-opencl.cl (original)
+++ cfe/trunk/test/CodeGen/blocks-opencl.cl Thu Mar  3 07:33:19 2016
@@ -2,15 +2,16 @@
 // This used to crash due to trying to generate a bitcase from a cstring
 // in the constant address space to i8* in AS0.
 
-void dummy(float (^op)(float))
-{
+void dummy(float (^const op)(float)) {
 }
 
 // CHECK: i8 addrspace(3)* getelementptr inbounds ([9 x i8], [9 x i8] addrspace(3)* @.str, i32 0, i32 0)
 
 kernel void test_block()
 {
-  float (^X)(float) = ^(float x) { return x + 42.0f; };
+  float (^const X)(float) = ^(float x) {
+    return x + 42.0f;
+  };
   dummy(X);
 }
 

Modified: cfe/trunk/test/SemaOpenCL/event_t.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/event_t.cl?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/event_t.cl (original)
+++ cfe/trunk/test/SemaOpenCL/event_t.cl Thu Mar  3 07:33:19 2016
@@ -3,7 +3,7 @@
 event_t glb_evt; // expected-error {{the event_t type cannot be used to declare a program scope variable}}
 
 constant struct evt_s {
-  event_t evt;  // expected-error {{the event_t type cannot be used to declare a structure or union field}}
+  event_t evt; // expected-error {{the 'event_t' type cannot be used to declare a structure or union field}}
 } evt_str = {0};
 
 void foo(event_t evt); // expected-note {{passing argument to parameter 'evt' here}}

Modified: cfe/trunk/test/SemaOpenCL/invalid-block.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/invalid-block.cl?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/invalid-block.cl (original)
+++ cfe/trunk/test/SemaOpenCL/invalid-block.cl Thu Mar  3 07:33:19 2016
@@ -1,20 +1,50 @@
 // RUN: %clang_cc1 -verify -fblocks -cl-std=CL2.0 %s
 
-int (^BlkVariadic)(int, ...) = ^int(int I, ...) { // expected-error {{invalid block prototype, variadic arguments are not allowed in OpenCL}}
+// OpenCL v2.0 s6.12.5
+
+// All blocks declarations must be const qualified and initialized.
+void f1() {
+  int (^bl1)() = ^() {}; // expected-error{{invalid block variable declaration - must be const qualified}}
+  int (^const bl2)(); // expected-error{{invalid block variable declaration - must be initialized}}
+  int (^const bl3)() = ^const(){
+  };
+}
+
+// A block with extern storage class is not allowed.
+extern int (^const bl)() = ^const(){}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}}
+void f2() {
+  extern int (^const bl)() = ^const(){}; // expected-error{{invalid block variable declaration - using 'extern' storage class is disallowed}}
+}
+
+// A block cannot be the return value of a function.
+typedef int (^const bl_t)(void);
+bl_t f3(bl_t bl); // expected-error{{declaring function return value of type 'bl_t' (aka 'int (^const)(void)') is not allowed}}
+
+struct bl_s {
+  int (^const bl)(void); // expected-error {{the 'int (^const)(void)' type cannot be used to declare a structure or union field}}
+};
+
+void f4() {
+  __block int a = 10; // expected-error {{the __block storage type is not permitted}}
+}
+
+// A block with variadic argument is not allowed.
+int (^const bl)(int, ...) = ^const int(int I, ...) { // expected-error {{invalid block prototype, variadic arguments are not allowed in OpenCL}}
   return 0;
 };
 
-typedef int (^BlkInt)(int);
-void f1(int i) {
-  BlkInt B1 = ^int(int I) {return 1;};
-  BlkInt B2 = ^int(int I) {return 2;};
-  BlkInt Arr[] = {B1, B2}; // expected-error {{array of 'BlkInt' (aka 'int (^)(int)') type is invalid in OpenCL}}
-  int tmp = i ? B1(i)      // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}}
-              : B2(i);     // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}}
+// A block can't be used to declare an array
+typedef int (^const bl1_t)(int);
+void f5(int i) {
+  bl1_t bl1 = ^const(int i) {return 1;};
+  bl1_t bl2 = ^const(int i) {return 2;};
+  bl1_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl1_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}}
 }
 
-void f2(BlkInt *BlockPtr) {
-  BlkInt B = ^int(int I) {return 1;};
-  BlkInt *P = &B; // expected-error {{invalid argument type 'BlkInt' (aka 'int (^)(int)') to unary expression}}
-  B = *BlockPtr;  // expected-error {{dereferencing pointer of type '__generic BlkInt *' (aka 'int (^__generic *)(int)') is not allowed in OpenCL}}
+void f6(bl1_t * bl_ptr) {
+  bl1_t bl = ^const(int i) {return 1;};
+  bl1_t *p = &bl; // expected-error {{invalid argument type 'bl1_t' (aka 'int (^const)(int)') to unary expression}}
+  bl = *bl_ptr;  // expected-error {{dereferencing pointer of type '__generic bl1_t *' (aka 'int (^const __generic *)(int)') is not allowed in OpenCL}}
 }

Modified: cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl (original)
+++ cfe/trunk/test/SemaOpenCL/invalid-kernel-parameters.cl Thu Mar  3 07:33:19 2016
@@ -24,7 +24,10 @@ kernel void bool_in_struct_arg(ContainsB
 
 typedef struct FooImage2D // expected-note{{within field of type 'FooImage2D' declared here}}
 {
-  image2d_t imageField; // expected-note{{field of illegal type 'image2d_t' declared here}}
+  // TODO: Clean up needed - we don't really need to check for image, event, etc
+  // as a note here any longer.
+  // They are diagnosed as an error for all struct fields (OpenCL v1.2 s6.9b,r).
+  image2d_t imageField; // expected-note{{field of illegal type 'image2d_t' declared here}} expected-error{{the 'image2d_t' type cannot be used to declare a structure or union field}}
 } FooImage2D;
 
 kernel void image_in_struct_arg(FooImage2D arg) { } // expected-error{{struct kernel parameters may not contain pointers}}

Modified: cfe/trunk/test/SemaOpenCL/sampler_t.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/sampler_t.cl?rev=262616&r1=262615&r2=262616&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/sampler_t.cl (original)
+++ cfe/trunk/test/SemaOpenCL/sampler_t.cl Thu Mar  3 07:33:19 2016
@@ -2,7 +2,11 @@
 
 constant sampler_t glb_smp = 5;
 
-void foo(sampler_t); 
+void foo(sampler_t);
+
+constant struct sampler_s {
+  sampler_t smp; // expected-error {{the 'sampler_t' type cannot be used to declare a structure or union field}}
+} sampler_str = {0};
 
 void kernel ker(sampler_t argsmp) {
   local sampler_t smp; // expected-error {{sampler type cannot be used with the __local and __global address space qualifiers}}




More information about the cfe-commits mailing list