diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 44c38396c764f..09e965aff2093 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -586,6 +586,8 @@ Bug Fixes in This Version ``#include`` directive. (#GH138094) - Fixed a crash during constant evaluation involving invalid lambda captures (#GH138832) +- Fixed a crash when instantiating an invalid dependent friend template specialization. + (#GH139052) - Fixed a crash with an invalid member function parameter list with a default argument which contains a pragma. (#GH113722) - Fixed assertion failures when generating name lookup table in modules. (#GH61065, #GH134739) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index cbccb567e2adf..d915448d0feb1 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18740,7 +18740,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // a template-id, the function name is not unqualified because these is // no name. While the wording requires some reading in-between the // lines, GCC, MSVC, and EDG all consider a friend function - // specialization definitions // to be de facto explicit specialization + // specialization definitions to be de facto explicit specialization // and diagnose them as such. } else if (isTemplateId) { Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7940340064eda..486414ea84861 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -9383,7 +9383,10 @@ bool Sema::CheckFunctionTemplateSpecialization( // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. - if (!isFriend) { + // A dependent friend specialization which has a definition should be treated + // as explicit specialization, despite being invalid. + if (FunctionDecl *InstFrom = FD->getInstantiatedFromMemberFunction(); + !isFriend || (InstFrom && InstFrom->getDependentSpecializationInfo())) { // Since explicit specializations do not inherit '=delete' from their // primary function template - check if the 'specialization' that was // implicitly generated (during template argument deduction for partial @@ -11370,7 +11373,12 @@ class ExplicitSpecializationVisibilityChecker { template void checkImpl(SpecDecl *Spec) { bool IsHiddenExplicitSpecialization = false; - if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { + TemplateSpecializationKind SpecKind = Spec->getTemplateSpecializationKind(); + // Some invalid friend declarations are written as specializations but are + // instantiated implicitly. + if constexpr (std::is_same_v) + SpecKind = Spec->getTemplateSpecializationKindForInstantiation(); + if (SpecKind == TSK_ExplicitSpecialization) { IsHiddenExplicitSpecialization = Spec->getMemberSpecializationInfo() ? !CheckMemberSpecialization(Spec) : !CheckExplicitSpecialization(Spec); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 01065f22b34a8..d4f99c1fa16f6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5756,8 +5756,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, RebuildTypeSourceInfoForDefaultSpecialMembers(); SetDeclDefaulted(Function, PatternDecl->getLocation()); } else { - NamedDecl *ND = Function; - DeclContext *DC = ND->getLexicalDeclContext(); + DeclContext *DC = Function->getLexicalDeclContext(); std::optional> Innermost; if (auto *Primary = Function->getPrimaryTemplate(); Primary && diff --git a/clang/test/SemaTemplate/GH55509.cpp b/clang/test/SemaTemplate/GH55509.cpp index 773a84305a0cd..b1ba8e513356d 100644 --- a/clang/test/SemaTemplate/GH55509.cpp +++ b/clang/test/SemaTemplate/GH55509.cpp @@ -110,3 +110,38 @@ namespace regression2 { } template void A::f(); } // namespace regression2 + +namespace GH139226 { + +struct FakeStream {}; + +template +class BinaryTree; + +template +FakeStream& operator<<(FakeStream& os, BinaryTree& b); + +template +FakeStream& operator>>(FakeStream& os, BinaryTree& b) { + return os; +} + +template +struct BinaryTree { + T* root{}; + friend FakeStream& operator<< (FakeStream& os, BinaryTree&) { + // expected-error@-1 {{friend function specialization cannot be defined}} + return os; + } + + friend FakeStream& operator>> (FakeStream& os, BinaryTree&); +}; + +void foo() { + FakeStream fakeout; + BinaryTree a{}; + fakeout << a; + fakeout >> a; +} + +}