https://github.com/piotrrak updated 
https://github.com/llvm/llvm-project/pull/153459

>From 4336c583847fde72a9357b40ae30258d32dea89f Mon Sep 17 00:00:00 2001
From: Piotr Rak <piotr....@gmail.com>
Date: Wed, 30 Jul 2025 03:05:35 +0200
Subject: [PATCH] [OpenCLCpp] Remove address-space from friend declaration

OpenCL prohibits address-space on function, however it
default address-space is implicitly to all member decls.

This causes the lookup to fail find correct free function or free function
template as it is considered different declaration.

This change also makes sure that hidden friend definition doesn't have
associated address-space.

Without this change friend declaration would cause incorrect diagnostic:

'test/SemaCXX/friend.cpp Line 16: conflicting types for 'f'`

in case of prior definition of function f friend declaration was refering to

While bit unsatisfactory it was much easier to fix/remove address-space of
friend declaration since it is still required for friend of member function
decls.

This change also enables compilation of some of failing test exposing this 
defect.

It was originally exhibited by 'test/SemaCXX/type-traits.cpp', however this test
has currently other issues also related to the __cl_clang_function_pointers
extension and address-space inferrence preventing from enabling it by the 
defaut.
---
 clang/include/clang/AST/Type.h                 |  6 ++++++
 clang/include/clang/Sema/SemaOpenCL.h          |  3 +++
 clang/lib/Sema/SemaDecl.cpp                    |  6 ++++++
 clang/lib/Sema/SemaOpenCL.cpp                  | 12 ++++++++++++
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp |  6 ++++++
 clang/test/SemaCXX/friend-template-redecl.cpp  |  1 +
 clang/test/SemaCXX/friend.cpp                  |  1 +
 clang/test/SemaCXX/friend2.cpp                 | 11 ++++++-----
 8 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index c4c23c835ebc2..c3c3902a00731 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5349,6 +5349,12 @@ class FunctionProtoType final
       return Result;
     }
 
+    ExtProtoInfo withoutAddressSpace() {
+      ExtProtoInfo Result(*this);
+      Result.TypeQuals = TypeQuals.withoutAddressSpace();
+      return Result;
+    }
+
     bool requiresFunctionProtoTypeExtraBitfields() const {
       return ExceptionSpec.Type == EST_Dynamic ||
              requiresFunctionProtoTypeArmAttributes() ||
diff --git a/clang/include/clang/Sema/SemaOpenCL.h 
b/clang/include/clang/Sema/SemaOpenCL.h
index 04b2b617fb12f..715b5845f2151 100644
--- a/clang/include/clang/Sema/SemaOpenCL.h
+++ b/clang/include/clang/Sema/SemaOpenCL.h
@@ -100,6 +100,9 @@ class SemaOpenCL : public SemaBase {
   bool checkBuiltinKernelWorkGroupSize(CallExpr *TheCall);
 
   bool checkBuiltinNDRangeAndBlock(CallExpr *TheCall);
+
+  void removeFriendFunctionAddressSpace(FunctionDecl *FD,
+                                        TypeSourceInfo *TInfo);
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index cb59782b83304..ff641ee033928 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -51,6 +51,7 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/SemaObjC.h"
 #include "clang/Sema/SemaOpenACC.h"
+#include "clang/Sema/SemaOpenCL.h"
 #include "clang/Sema/SemaOpenMP.h"
 #include "clang/Sema/SemaPPC.h"
 #include "clang/Sema/SemaRISCV.h"
@@ -10300,6 +10301,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, 
DeclContext *DC,
       }
       NewFD->setObjectOfFriendDecl();
       NewFD->setAccess(AS_public);
+      // For OpenCLCPlusPlus dialect remove address space from free friend
+      // function prototype, since it is non-member and none should be present.
+      if (!isa<CXXMethodDecl>(NewFD) && getLangOpts().OpenCLCPlusPlus) {
+        OpenCL().removeFriendFunctionAddressSpace(NewFD, TInfo);
+      }
     }
 
     // If a function is defined as defaulted or deleted, mark it as such now.
diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp
index f11a40e3964ff..c7b6d9d505b26 100644
--- a/clang/lib/Sema/SemaOpenCL.cpp
+++ b/clang/lib/Sema/SemaOpenCL.cpp
@@ -576,4 +576,16 @@ bool SemaOpenCL::checkBuiltinToAddr(unsigned BuiltinID, 
CallExpr *Call) {
   return false;
 }
 
+void SemaOpenCL::removeFriendFunctionAddressSpace(FunctionDecl *FD,
+                                                  TypeSourceInfo *TInfo) {
+  assert(!isa<CXXMethodDecl>(FD) && "Only free function should be adjusted");
+
+  // For generic address space remove __generic, otherwise remove __private
+  QualType R = TInfo->getType();
+  const FunctionProtoType *FPT = R->getAs<FunctionProtoType>();
+  FD->setType(SemaRef.Context.getFunctionType(
+      FPT->getReturnType(), FPT->getParamTypes(),
+      FPT->getExtProtoInfo().withoutAddressSpace()));
+}
+
 } // namespace clang
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f02a295220efb..a925e12786806 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -29,6 +29,7 @@
 #include "clang/Sema/SemaCUDA.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaObjC.h"
+#include "clang/Sema/SemaOpenCL.h"
 #include "clang/Sema/SemaOpenMP.h"
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/Template.h"
@@ -2823,6 +2824,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
 
   if (isFriend) {
     Function->setObjectOfFriendDecl();
+    // For OpenCLCPlusPlus dialect remove address space (__generic/__private)
+    // of dependend or template free friend function instantiation.
+    if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
+      SemaRef.OpenCL().removeFriendFunctionAddressSpace(Function, TInfo);
+    }
     if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate())
       FT->setObjectOfFriendDecl();
   }
diff --git a/clang/test/SemaCXX/friend-template-redecl.cpp 
b/clang/test/SemaCXX/friend-template-redecl.cpp
index 4ee03c6f6387f..384291a87b198 100644
--- a/clang/test/SemaCXX/friend-template-redecl.cpp
+++ b/clang/test/SemaCXX/friend-template-redecl.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -cl-std=clc++2021 -verify -emit-llvm-only %s
 
 template <class T> void bar(const T &t) { foo(t); }
 
diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp
index 53e6bbfcf42a8..3622b71ee3106 100644
--- a/clang/test/SemaCXX/friend.cpp
+++ b/clang/test/SemaCXX/friend.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
+// RUN: %clang_cc1 -fsyntax-only -verify %s -cl-std=clc++2021
 
 friend class A; // expected-error {{'friend' used outside of class}}
 void f() { friend class A; } // expected-error {{'friend' used outside of 
class}}
diff --git a/clang/test/SemaCXX/friend2.cpp b/clang/test/SemaCXX/friend2.cpp
index 6d3b545904e48..6c8fe20b7c914 100644
--- a/clang/test/SemaCXX/friend2.cpp
+++ b/clang/test/SemaCXX/friend2.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,expected-noncl %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,expected-cl %s 
-cl-std=clc++2021
 
 // If a friend function is defined in several non-template classes,
 // it is an error.
@@ -62,16 +63,16 @@ template<typename T> struct C6b {
   friend void func6(int) {}  // expected-error{{redefinition of 'func6'}}
 };
 C6a<long> c6a;
-C6b<int*> c6b;  // expected-note{{in instantiation of template class 'C6b<int 
*>' requested here}}
-
+C6b<int*> c6b;  // expected-noncl-note{{in instantiation of template class 
'C6b<int *>' requested here}}
+                // expected-cl-note@-1{{in instantiation of template class 
'C6b<__generic int *>' requested here}}
 void func7(int);
 template<typename T> struct C7 {
   friend void func7(int) {}  // expected-error{{redefinition of 'func7'}}
                              // expected-note@-1{{previous definition is here}}
 };
 C7<long> c7a;
-C7<int*> c7b;  // expected-note{{in instantiation of template class 'C7<int 
*>' requested here}}
-
+C7<int*> c7b;  // expected-noncl-note{{in instantiation of template class 
'C7<int *>' requested here}}
+               // expected-cl-note@-1{{in instantiation of template class 
'C7<__generic int *>' requested here}}
 
 // Even if clases are not instantiated and hence friend functions defined in 
them are not
 // available, their declarations can be checked.

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to