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