diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index cfbb9de4f2a06..b95d3c9b710ac 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5369,6 +5369,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 8ddbaf34a7f47..a28db97e078c8 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" @@ -10308,6 +10309,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(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(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(); + 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 6b423ce06523a..1e2b64d376ed9 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 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 struct C6b { friend void func6(int) {} // expected-error{{redefinition of 'func6'}} }; C6a c6a; -C6b c6b; // expected-note{{in instantiation of template class 'C6b' requested here}} - +C6b c6b; // expected-noncl-note{{in instantiation of template class 'C6b' requested here}} + // expected-cl-note@-1{{in instantiation of template class 'C6b<__generic int *>' requested here}} void func7(int); template struct C7 { friend void func7(int) {} // expected-error{{redefinition of 'func7'}} // expected-note@-1{{previous definition is here}} }; C7 c7a; -C7 c7b; // expected-note{{in instantiation of template class 'C7' requested here}} - +C7 c7b; // expected-noncl-note{{in instantiation of template class 'C7' 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.