Anastasia updated this revision to Diff 48219.
Anastasia added a comment.

Drafted code for printf handling.

Made me think about:

1. How much signature check should we do i.e. should we check the pointer AS 
itself (generic for CL2.0, any other otherwise) or qualifiers being used for 
the first parameter (const, volatile ...)?
2. Would it be nicer to just add printf as a Clang OpenCL builitin to prevent 
it being declared in various ways and avoid writing custom signature check as 
in this change?


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,4 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL2.0 -DCL20
+
+void foo(int, ...); // expected-error{{OpenCL does not allow variadic arguments}}
+int printf(constant const char *, ...);
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 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 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,39 @@
         }
       }
 
+      // All OpenCL misc checks
+      if (LangOpts.OpenCL) {
+        // OpenCL v1.2 s6.9 - Variadic functions are not supported, except for
+        // printf
+        // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not
+        // allowed
+        if (FTI.isVariadic) {
+          bool IsValidOCLPrintf = false;
+          if (D.getIdentifier()->getName() == "printf" && FTI.NumParams > 0) {
+            ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[0].Param);
+            QualType ParamTy = Param->getType();
+            if (ParamTy->isPointerType() &&
+                ParamTy->getPointeeType().getAddressSpace() ==
+                    LangAS::opencl_constant &&
+                ParamTy->getPointeeType()->isCharType()) {
+              IsValidOCLPrintf = true;
+            }
+          }
+          if (!IsValidOCLPrintf) {
+            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
@@ -6564,7 +6564,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 &&
@@ -6574,12 +6574,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 ||
@@ -10027,6 +10047,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 &&
@@ -13067,10 +13099,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 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();
   }
 
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">,
@@ -7667,8 +7667,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<
@@ -7695,6 +7695,8 @@
   " 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_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<
@@ -7710,6 +7712,14 @@
 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 {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to