From 50aa5b64f6d2cf98706bfb4792f274bd071e3b9c Mon Sep 17 00:00:00 2001 From: Qizhi Hu <836744285@qq.com> Date: Wed, 1 May 2024 02:25:04 +0800 Subject: [PATCH 1/2] [Clang][Sema] fix a bug on constraint check with template friend function --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Sema/SemaTemplateInstantiate.cpp | 14 +++++++ clang/test/SemaCXX/PR90349.cpp | 43 ++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 clang/test/SemaCXX/PR90349.cpp 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..1805f8f6e5ad9 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::Done(); + } + // 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..6a4b5c21e88f3 --- /dev/null +++ b/clang/test/SemaCXX/PR90349.cpp @@ -0,0 +1,43 @@ +// 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; +} From 3d27f11d79b00608bf9135bcc4b4cb859027933a Mon Sep 17 00:00:00 2001 From: Qizhi Hu <836744285@qq.com> Date: Thu, 2 May 2024 20:05:10 +0800 Subject: [PATCH 2/2] continue to handle context instead of finish --- clang/lib/Sema/SemaTemplateInstantiate.cpp | 2 +- clang/test/SemaCXX/PR90349.cpp | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 1805f8f6e5ad9..22789c72b2c90 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -292,7 +292,7 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function, if (TemplatePattern && FunctionPattern && TemplatePattern->getTemplateDepth() == FunctionPattern->getTemplateDepth()) - return Response::Done(); + return Response::UseNextDecl(Function); } // If this function is a generic lambda specialization, we are done. diff --git a/clang/test/SemaCXX/PR90349.cpp b/clang/test/SemaCXX/PR90349.cpp index 6a4b5c21e88f3..570a49fd2073b 100644 --- a/clang/test/SemaCXX/PR90349.cpp +++ b/clang/test/SemaCXX/PR90349.cpp @@ -41,3 +41,27 @@ 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