Anastasia created this revision.
Anastasia added reviewers: pekka.jaaskelainen, pxli168.
Anastasia added a subscriber: cfe-commits.
Anastasia set the repository for this revision to rL LLVM.

Applying the following restrictions for block variables in OpenCL (v2.0 
s6.12.5):

- __block storage class is disallowed
- variadic arguments are disallowed
- every block declaration must be const qualified and initialized
- a block can't be used as a return type of a function
- extern speficier is disallowed

This adds diagnostics missing from http://reviews.llvm.org/D16047

Repository:
  rL LLVM

http://reviews.llvm.org/D16928

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaType.cpp
  test/CodeGen/blocks-opencl.cl
  test/SemaOpenCL/event_t.cl
  test/SemaOpenCL/invalid-blocks-cl20.cl
  test/SemaOpenCL/invalid-func.cl
  test/SemaOpenCL/invalid-kernel-parameters.cl
  test/SemaOpenCL/sampler_t.cl

Index: test/SemaOpenCL/sampler_t.cl
===================================================================
--- test/SemaOpenCL/sampler_t.cl
+++ test/SemaOpenCL/sampler_t.cl
@@ -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}}
Index: test/SemaOpenCL/invalid-kernel-parameters.cl
===================================================================
--- test/SemaOpenCL/invalid-kernel-parameters.cl
+++ test/SemaOpenCL/invalid-kernel-parameters.cl
@@ -24,7 +24,10 @@
 
 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}}
Index: test/SemaOpenCL/invalid-func.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCL/invalid-func.cl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL2.0 -DCL20
+// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.2 -DCL12
+// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.1 -DCL11
+
+void foo(int, ...); // expected-error{{OpenCL does not allow variadic arguments}}
+int printf(const char *, ...);
+#ifdef CL11
+// expected-error{{OpenCL does not allow variadic arguments}}
+#endif
Index: test/SemaOpenCL/invalid-blocks-cl20.cl
===================================================================
--- /dev/null
+++ test/SemaOpenCL/invalid-blocks-cl20.cl
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL2.0 -fblocks
+
+// OpenCL v2.0 s6.12.5
+
+// All blocks declarations must be const qualified and initialised.
+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 initialised}}
+  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 with variadic argument is not allowed.
+typedef int (^const bl_t)(int, ...); // expected-error{{OpenCL does not allow variadic arguments}}
+
+// A block cannot be the return value 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 (^const)(int, ...)') is not allowed}}
+
+struct bl_s {
+  int (^bl)(void); // expected-error {{the 'int (^)(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}}
+}
Index: test/SemaOpenCL/event_t.cl
===================================================================
--- test/SemaOpenCL/event_t.cl
+++ test/SemaOpenCL/event_t.cl
@@ -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}}
Index: test/CodeGen/blocks-opencl.cl
===================================================================
--- test/CodeGen/blocks-opencl.cl
+++ test/CodeGen/blocks-opencl.cl
@@ -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);
 }
 
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -3811,7 +3811,8 @@
       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) {
@@ -3821,6 +3822,26 @@
         }
       }
 
+      // All OpenCL misc checks
+      if (LangOpts.OpenCL) {
+        // OpenCL v1.2 s6.9 doesn't support variadic functions, except for
+        // printf
+        // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not
+        // allowed
+        if (FTI.isVariadic && D.getIdentifier()->getName() != "printf") {
+          S.Diag(D.getIdentifierLoc(),
+                 diag::err_opencl_variadic_prototype_not_allowed);
+          D.setInvalidType(true);
+        }
+        // OpenCL v2.0 s6.12.5 - A block cannot be the return value of a
+        // function.
+        if (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()) {
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -6535,7 +6535,7 @@
     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 &&
@@ -6545,12 +6545,32 @@
     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;
+    }
+    // OpenCL v2.0 s6.12.5 - Any block declaration must be const qualified and
+    // can't use 'extern' storage class.
+    if (T->isBlockPointerType()) {
+      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 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 ||
@@ -9972,6 +9992,18 @@
 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 &&
@@ -12976,10 +13008,11 @@
     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 can 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();
   }
 
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -617,8 +617,8 @@
   "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">,
@@ -7651,8 +7651,8 @@
   "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<
@@ -7679,6 +7679,11 @@
   " 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_storage_type : Error<
+  "the __block storage type is not permitted">;
+
+def err_opencl_variadic_prototype_not_allowed : Error<
+  "OpenCL does not allow variadic arguments">;
 
 // OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions
 def err_opencl_builtin_pipe_first_arg : Error<
@@ -7694,6 +7699,12 @@
 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_invalid_block_declaration : Error<
+  "invalid block variable declaration - must be %select{const qualified|initialised}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 {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to