diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2c5308fbcb319..ac90e3933798c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -630,6 +630,7 @@ Bug Fixes to C++ Support - Fix a bug on template partial specialization with issue on deduction of nontype template parameter whose type is `decltype(auto)`. Fixes (#GH68885). - Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context. +- Fix a bug on constraint check with template friend function. Fixes (#GH90349). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3a9fd906b7af8..22789c72b2c90 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -281,6 +281,20 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function, if (Function->getPrimaryTemplate()->isMemberSpecialization()) return Response::Done(); + if (Function->getFriendObjectKind()) + if (const ClassTemplateSpecializationDecl *TD = + dyn_cast( + Function->getLexicalDeclContext())) { + const CXXRecordDecl *TemplatePattern = + TD->getTemplateInstantiationPattern(); + const FunctionDecl *FunctionPattern = + Function->getTemplateInstantiationPattern(); + if (TemplatePattern && FunctionPattern && + TemplatePattern->getTemplateDepth() == + FunctionPattern->getTemplateDepth()) + return Response::UseNextDecl(Function); + } + // If this function is a generic lambda specialization, we are done. if (!ForConstraintInstantiation && isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) { diff --git a/clang/test/SemaCXX/PR90349.cpp b/clang/test/SemaCXX/PR90349.cpp new file mode 100644 index 0000000000000..570a49fd2073b --- /dev/null +++ b/clang/test/SemaCXX/PR90349.cpp @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s + +// expected-no-diagnostics + +namespace std { +template +concept floating_point = __is_same(T,double) || __is_same(T,float); + +template +concept integral = __is_same(T,int); + +} + +template +class Blob; + +template +Blob MakeBlob(); + +template +class Blob { +private: + Blob() {} + + friend Blob MakeBlob(); +}; + +template +Blob MakeBlob() +{ + return Blob(); +} + +template +Blob FindBlobs() +{ + return MakeBlob(); +} + +int main(int argc, const char * argv[]) { + FindBlobs(); + return 0; +} + +template +concept D = sizeof(T) == sizeof(U); + +template +struct A +{ + template requires D + static void f(); +}; + +template +struct B +{ + template + struct C + { + friend void A::f(); + }; +}; + +template struct B::C; + +extern template void A::f(); // crash here