This revision was automatically updated to reflect the committed changes.
Closed by commit rG4fde2b6a0c08: [OpenCL] Add clang extension for function 
pointers. (authored by Anastasia).
Herald added a project: clang.

Changed prior to commit:
  https://reviews.llvm.org/D94021?vs=314411&id=314963#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D94021/new/

https://reviews.llvm.org/D94021

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/OpenCLExtensions.def
  clang/lib/Basic/Targets/AMDGPU.h
  clang/lib/Basic/Targets/NVPTX.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/Misc/amdgcn.languageOptsOpenCL.cl
  clang/test/Misc/nvptx.languageOptsOpenCL.cl
  clang/test/Misc/r600.languageOptsOpenCL.cl
  clang/test/Parser/opencl-cxx-virtual.cl
  clang/test/SemaOpenCL/extension-version.cl
  clang/test/SemaOpenCL/func.cl
  clang/test/SemaOpenCLCXX/members.cl

Index: clang/test/SemaOpenCLCXX/members.cl
===================================================================
--- clang/test/SemaOpenCLCXX/members.cl
+++ clang/test/SemaOpenCLCXX/members.cl
@@ -1,6 +1,13 @@
 //RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -verify -fsyntax-only
+//RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -verify -fsyntax-only -DFUNCPTREXT
+
+#ifdef FUNCPTREXT
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
+//expected-no-diagnostics
+#endif
 
 // Check that pointer to member functions are diagnosed
+// unless specific clang extension is enabled.
 struct C {
   void f(int n);
 };
@@ -12,11 +19,25 @@
 
 template <typename T>
 void templ_test() {
-  typename remove_reference<T>::type *ptr; //expected-error{{pointers to functions are not allowed}}
+  typename remove_reference<T>::type *ptr;
+#ifndef FUNCPTREXT
+  //expected-error@-2{{pointers to functions are not allowed}}
+#endif
 }
 
 void test() {
-  void (C::*p)(int);       //expected-error{{pointers to functions are not allowed}}
-  p_t p1;                  //expected-error{{pointers to functions are not allowed}}
-  templ_test<int (&)()>(); //expected-note{{in instantiation of function template specialization}}
+  void (C::*p)(int);
+#ifndef FUNCPTREXT
+//expected-error@-2{{pointers to functions are not allowed}}
+#endif
+
+  p_t p1;
+#ifndef FUNCPTREXT
+//expected-error@-2{{pointers to functions are not allowed}}
+#endif
+
+  templ_test<int (&)()>();
+#ifndef FUNCPTREXT
+//expected-note@-2{{in instantiation of function template specialization}}
+#endif
 }
Index: clang/test/SemaOpenCL/func.cl
===================================================================
--- clang/test/SemaOpenCL/func.cl
+++ clang/test/SemaOpenCL/func.cl
@@ -1,16 +1,26 @@
 // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -triple spir-unknown-unknown
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -triple spir-unknown-unknown -DFUNCPTREXT
+
+#ifdef FUNCPTREXT
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
+#endif
 
 // 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}}
-                                            // expected-error@-1{{pointers to functions are not allowed}}
+#ifndef FUNCPTREXT
+// expected-error@-2 {{pointers to functions are not allowed}}
+#endif
 int printf(__constant const char *st, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
 
 // Struct type with function pointer field
 typedef struct s
 {
-   void (*f)(struct s *self, int *i);       // expected-error{{pointers to functions are not allowed}}
+   void (*f)(struct s *self, int *i);
+#ifndef FUNCPTREXT
+// expected-error@-2 {{pointers to functions are not allowed}}
+#endif
 } s_t;
 
 //Function pointer
@@ -22,7 +32,10 @@
 void bar()
 {
   // declaring a function pointer is an error
-  void (*fptr)(int); // expected-error{{pointers to functions are not allowed}}
+  void (*fptr)(int);
+#ifndef FUNCPTREXT
+  // expected-error@-2 {{pointers to functions are not allowed}}
+#endif
 
   // taking the address of a function is an error
   foo((void*)foo); // expected-error{{taking address of function is not allowed}}
Index: clang/test/SemaOpenCL/extension-version.cl
===================================================================
--- clang/test/SemaOpenCL/extension-version.cl
+++ clang/test/SemaOpenCL/extension-version.cl
@@ -17,7 +17,12 @@
 #ifndef cl_clang_storage_class_specifiers
 #error "Missing cl_clang_storage_class_specifiers define"
 #endif
-#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
+#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
+
+#ifndef __cl_clang_function_pointers
+#error "Missing __cl_clang_function_pointers define"
+#endif
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
 
 #ifndef cl_khr_fp16
 #error "Missing cl_khr_fp16 define"
Index: clang/test/Parser/opencl-cxx-virtual.cl
===================================================================
--- clang/test/Parser/opencl-cxx-virtual.cl
+++ clang/test/Parser/opencl-cxx-virtual.cl
@@ -1,19 +1,32 @@
 // RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -fsyntax-only -verify -DFUNCPTREXT
 
-// Test that virtual functions and abstract classes are rejected.
+#ifdef FUNCPTREXT
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
+//expected-no-diagnostics
+#endif
+
+// Test that virtual functions and abstract classes are rejected
+// unless specific clang extension is used.
 class virtual_functions {
   virtual void bad1() {}
-  //expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
+#ifndef FUNCPTREXT
+  //expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}}
+#endif
 
   virtual void bad2() = 0;
-  //expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
-  //expected-error@-2 {{'bad2' is not virtual and cannot be declared pure}}
+#ifndef FUNCPTREXT
+  //expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}}
+  //expected-error@-3 {{'bad2' is not virtual and cannot be declared pure}}
+#endif
 };
 
 template <typename T>
 class X {
   virtual T f();
-  //expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
+#ifndef FUNCPTREXT
+  //expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}}
+#endif
 };
 
 // Test that virtual base classes are allowed.
Index: clang/test/Misc/r600.languageOptsOpenCL.cl
===================================================================
--- clang/test/Misc/r600.languageOptsOpenCL.cl
+++ clang/test/Misc/r600.languageOptsOpenCL.cl
@@ -28,7 +28,12 @@
 #ifndef cl_clang_storage_class_specifiers
 #error "Missing cl_clang_storage_class_specifiers define"
 #endif
-#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
+#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
+
+#ifndef __cl_clang_function_pointers
+#error "Missing __cl_clang_function_pointers define"
+#endif
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
 
 #ifdef cl_khr_fp16
 #error "Incorrect cl_khr_fp16 define"
Index: clang/test/Misc/nvptx.languageOptsOpenCL.cl
===================================================================
--- clang/test/Misc/nvptx.languageOptsOpenCL.cl
+++ clang/test/Misc/nvptx.languageOptsOpenCL.cl
@@ -20,7 +20,12 @@
 #ifndef cl_clang_storage_class_specifiers
 #error "Missing cl_clang_storage_class_specifiers define"
 #endif
-#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
+#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
+
+#ifndef __cl_clang_function_pointers
+#error "Missing __cl_clang_function_pointers define"
+#endif
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
 
 #ifdef cl_khr_fp16
 #error "Incorrect cl_khr_fp16 define"
Index: clang/test/Misc/amdgcn.languageOptsOpenCL.cl
===================================================================
--- clang/test/Misc/amdgcn.languageOptsOpenCL.cl
+++ clang/test/Misc/amdgcn.languageOptsOpenCL.cl
@@ -12,7 +12,12 @@
 #ifndef cl_clang_storage_class_specifiers
 #error "Missing cl_clang_storage_class_specifiers define"
 #endif
-#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
+#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
+
+#ifndef __cl_clang_function_pointers
+#error "Missing __cl_clang_function_pointers define"
+#endif
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
 
 #ifndef cl_khr_fp16
 #error "Missing cl_khr_fp16 define"
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2089,7 +2089,8 @@
     return QualType();
   }
 
-  if (T->isFunctionType() && getLangOpts().OpenCL) {
+  if (T->isFunctionType() && getLangOpts().OpenCL &&
+      !getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) {
     Diag(Loc, diag::err_opencl_function_pointer);
     return QualType();
   }
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -6748,14 +6748,16 @@
   }
 
   // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
-  QualType NR = R;
-  while (NR->isPointerType() || NR->isMemberFunctionPointerType()) {
-    if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType()) {
-      Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
-      D.setInvalidType();
-      return false;
+  if (!Se.getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) {
+    QualType NR = R;
+    while (NR->isPointerType() || NR->isMemberFunctionPointerType()) {
+      if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType()) {
+        Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
+        D.setInvalidType();
+        return false;
+      }
+      NR = NR->getPointeeType();
     }
-    NR = NR->getPointeeType();
   }
 
   if (!Se.getOpenCLOptions().isEnabled("cl_khr_fp16")) {
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -3630,12 +3630,13 @@
     case tok::kw_virtual:
       // C++ for OpenCL does not allow virtual function qualifier, to avoid
       // function pointers restricted in OpenCL v2.0 s6.9.a.
-      if (getLangOpts().OpenCLCPlusPlus) {
+      if (getLangOpts().OpenCLCPlusPlus &&
+          !getActions().getOpenCLOptions().isEnabled(
+              "__cl_clang_function_pointers")) {
         DiagID = diag::err_openclcxx_virtual_function;
         PrevSpec = Tok.getIdentifierInfo()->getNameStart();
         isInvalid = true;
-      }
-      else {
+      } else {
         isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
       }
       break;
Index: clang/lib/Basic/Targets/NVPTX.h
===================================================================
--- clang/lib/Basic/Targets/NVPTX.h
+++ clang/lib/Basic/Targets/NVPTX.h
@@ -128,6 +128,7 @@
   void setSupportedOpenCLOpts() override {
     auto &Opts = getSupportedOpenCLOpts();
     Opts.support("cl_clang_storage_class_specifiers");
+    Opts.support("__cl_clang_function_pointers");
 
     Opts.support("cl_khr_fp64");
     Opts.support("cl_khr_byte_addressable_store");
Index: clang/lib/Basic/Targets/AMDGPU.h
===================================================================
--- clang/lib/Basic/Targets/AMDGPU.h
+++ clang/lib/Basic/Targets/AMDGPU.h
@@ -285,6 +285,7 @@
   void setSupportedOpenCLOpts() override {
     auto &Opts = getSupportedOpenCLOpts();
     Opts.support("cl_clang_storage_class_specifiers");
+    Opts.support("__cl_clang_function_pointers");
 
     bool IsAMDGCN = isAMDGCN(getTriple());
 
Index: clang/include/clang/Basic/OpenCLExtensions.def
===================================================================
--- clang/include/clang/Basic/OpenCLExtensions.def
+++ clang/include/clang/Basic/OpenCLExtensions.def
@@ -69,6 +69,7 @@
 
 // Clang Extensions.
 OPENCLEXT_INTERNAL(cl_clang_storage_class_specifiers, 100, ~0U)
+OPENCLEXT_INTERNAL(__cl_clang_function_pointers, 100, ~0U)
 
 // AMD OpenCL extensions
 OPENCLEXT_INTERNAL(cl_amd_media_ops, 100, ~0U)
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -1722,6 +1722,58 @@
 For GCC compatibility, ``__builtin_complex(re, im)`` can also be used to
 construct a complex number from the given real and imaginary components.
 
+OpenCL Features
+===============
+
+Clang supports internal OpenCL extensions documented below.
+
+``__cl_clang_function_pointers``
+--------------------------------
+
+With this extension it is possible to enable various language features that
+are relying on function pointers using regular OpenCL extension pragma
+mechanism detailed in `the OpenCL Extension Specification,
+section 1.2
+<https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_Ext.html#extensions-overview>`_.
+
+In C++ for OpenCL this also enables:
+
+- Use of member function pointers;
+
+- Unrestricted use of references to functions;
+
+- Virtual member functions.
+
+Such functionality is not conformant and does not guarantee to compile
+correctly in any circumstances. It can be used if:
+
+- the kernel source does not contain call expressions to (member-) function
+  pointers, or virtual functions. For example this extension can be used in
+  metaprogramming algorithms to be able to specify/detect types generically.
+
+- the generated kernel binary does not contain indirect calls because they
+  are eliminated using compiler optimizations e.g. devirtualization. 
+
+- the selected target supports the function pointer like functionality e.g.
+  most CPU targets.
+
+**Example of Use**:
+
+.. code-block:: c++
+
+  #pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
+  void foo()
+  {
+    void (*fp)(); // compiled - no diagnostic generated
+  }
+
+  #pragma OPENCL EXTENSION __cl_clang_function_pointers : disable
+  void bar()
+  {
+    void (*fp)(); // error - pointers to function are not allowed
+  }
+
+
 Builtin Functions
 =================
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to