Anastasia created this revision.
Anastasia added a reviewer: mantognini.
Herald added subscribers: ebevhan, yaxunl.
Anastasia requested review of this revision.

References to functions are less permissive than pointers to functions and 
therefore some use cases could be allowed for example:

- For local variables
- For non-extern static and global variables
- For template parameters that are not used as function parameters or class 
members
- In constexpr

However, more language work is needed to analyze the invalid/valid cases. This 
can be done in the future language versions if there is enough interest in the 
feature from the application developers. Even if we had  a request for allowing 
some function pointer functionality (PR44788), OpenCL has never adopted the 
feature as a part of the standard and therefore many applications have been 
written successfully without it. On the other hand C++ provides other related 
features - lambdas and function objects that are allowed in OpenCL and can be 
used to express some sort of the indirect function call logic. For now it seems 
reasonable to just disallow the references to functions just like we disallow 
function pointers. This prevents erroneous programs from being compiled 
silently.

Note that for the advanced users there is the following extension available 
`__cl_clang_function_pointers` that can be used if there is knowledge about the 
application sources or compilation options to make sure the non-conformant 
functionality is safe (more details are in 
https://clang.llvm.org/docs/LanguageExtensions.html#opencl-features).


https://reviews.llvm.org/D95442

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/SemaOpenCLCXX/references.cl


Index: clang/test/SemaOpenCLCXX/references.cl
===================================================================
--- /dev/null
+++ clang/test/SemaOpenCLCXX/references.cl
@@ -0,0 +1,43 @@
+//RUN: %clang_cc1 %s -cl-std=clc++ -verify -fsyntax-only
+//RUN: %clang_cc1 %s -cl-std=clc++ -verify -fsyntax-only -DFPTREXT
+
+#ifdef FPTREXT
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
+#endif // FPTREXT
+
+// References to functions are not allowed.
+struct myclass {
+  void (&mem)();
+//FIXME: Here we provide incorrect diagnostic.
+#ifndef FPTREXT
+//expected-error@-3{{reference to function type cannot have '__generic' 
qualifier}}
+#endif // FPTREXT
+};
+
+void (&glob)();
+#ifndef FPTREXT
+//expected-error@-2{{references to functions are not allowed}}
+//expected-error@-3{{declaration of reference variable 'glob' requires an 
initializer}}
+#endif // FPTREXT
+template <typename T>
+void templ() {
+  // FIXME: We miss to diagnose the reference to function.
+  T loc; //expected-error{{declaration of reference variable 'loc' requires an 
initializer}}
+}
+
+void foo();
+void test(void (&par)()) {
+  void (&loc)();
+#ifndef FPTREXT
+//expected-error@-2{{references to functions are not allowed}}
+//expected-error@-3{{declaration of reference variable 'loc' requires an 
initializer}}
+#endif // FPTREXT
+
+  void (*&ref2fptr)();
+#ifndef FPTREXT
+//expected-error@-2{{pointers to functions are not allowed}}
+//expected-error@-3{{declaration of reference variable 'ref2fptr' requires an 
initializer}}
+#endif // FPTREXT
+
+  templ<void (&)()>(); //expected-note{{in instantiation of function template 
specialization}}
+}
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2091,7 +2091,7 @@
 
   if (T->isFunctionType() && getLangOpts().OpenCL &&
       !getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) {
-    Diag(Loc, diag::err_opencl_function_pointer);
+    Diag(Loc, diag::err_opencl_function_pointer) << /*pointer*/ 0;
     return QualType();
   }
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -6752,9 +6752,12 @@
   // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
   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);
+    while (NR->isPointerType() || NR->isMemberFunctionPointerType() ||
+           NR->isReferenceType()) {
+      if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType() ||
+          NR->isFunctionReferenceType()) {
+        Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer)
+            << NR->isReferenceType();
         D.setInvalidType();
         return false;
       }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8541,7 +8541,7 @@
   "of different size">;
 
 def err_opencl_function_pointer : Error<
-  "pointers to functions are not allowed">;
+  "%select{pointers|references}0 to functions are not allowed">;
 
 def err_opencl_taking_address_capture : Error<
   "taking address of a capture is not allowed">;


Index: clang/test/SemaOpenCLCXX/references.cl
===================================================================
--- /dev/null
+++ clang/test/SemaOpenCLCXX/references.cl
@@ -0,0 +1,43 @@
+//RUN: %clang_cc1 %s -cl-std=clc++ -verify -fsyntax-only
+//RUN: %clang_cc1 %s -cl-std=clc++ -verify -fsyntax-only -DFPTREXT
+
+#ifdef FPTREXT
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
+#endif // FPTREXT
+
+// References to functions are not allowed.
+struct myclass {
+  void (&mem)();
+//FIXME: Here we provide incorrect diagnostic.
+#ifndef FPTREXT
+//expected-error@-3{{reference to function type cannot have '__generic' qualifier}}
+#endif // FPTREXT
+};
+
+void (&glob)();
+#ifndef FPTREXT
+//expected-error@-2{{references to functions are not allowed}}
+//expected-error@-3{{declaration of reference variable 'glob' requires an initializer}}
+#endif // FPTREXT
+template <typename T>
+void templ() {
+  // FIXME: We miss to diagnose the reference to function.
+  T loc; //expected-error{{declaration of reference variable 'loc' requires an initializer}}
+}
+
+void foo();
+void test(void (&par)()) {
+  void (&loc)();
+#ifndef FPTREXT
+//expected-error@-2{{references to functions are not allowed}}
+//expected-error@-3{{declaration of reference variable 'loc' requires an initializer}}
+#endif // FPTREXT
+
+  void (*&ref2fptr)();
+#ifndef FPTREXT
+//expected-error@-2{{pointers to functions are not allowed}}
+//expected-error@-3{{declaration of reference variable 'ref2fptr' requires an initializer}}
+#endif // FPTREXT
+
+  templ<void (&)()>(); //expected-note{{in instantiation of function template specialization}}
+}
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2091,7 +2091,7 @@
 
   if (T->isFunctionType() && getLangOpts().OpenCL &&
       !getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) {
-    Diag(Loc, diag::err_opencl_function_pointer);
+    Diag(Loc, diag::err_opencl_function_pointer) << /*pointer*/ 0;
     return QualType();
   }
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -6752,9 +6752,12 @@
   // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
   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);
+    while (NR->isPointerType() || NR->isMemberFunctionPointerType() ||
+           NR->isReferenceType()) {
+      if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType() ||
+          NR->isFunctionReferenceType()) {
+        Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer)
+            << NR->isReferenceType();
         D.setInvalidType();
         return false;
       }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8541,7 +8541,7 @@
   "of different size">;
 
 def err_opencl_function_pointer : Error<
-  "pointers to functions are not allowed">;
+  "%select{pointers|references}0 to functions are not allowed">;
 
 def err_opencl_taking_address_capture : Error<
   "taking address of a capture is not allowed">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to