https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/139436
Since 346077aa, we began using the primary template's lexical DeclContext for template arguments in order to properly instantiate a friend definition. There is a missed peculiar case, as in a friend template is specialized within a dependent context. In this scenario, the primary template is not a definition, whereas the specialization is. So the primary template's DeclContext doesn't provide any meaningful for instantiation. Fixes https://github.com/llvm/llvm-project/issues/139052 >From 1756fbcd874097fdea256c2c5986810a011eafed Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sun, 11 May 2025 12:54:12 +0800 Subject: [PATCH] [Clang] Stop looking for DC from dependent friend specializations Since 346077aa, we began using the primary template's lexical DeclContext for template arguments in order to properly instantiate a friend definition. There is a missed peculiar case, as in a friend template is specialized within a dependent context. In this scenario, the primary template is not a definition, whereas the specialization is. So the primary template's DeclContext doesn't provide any meaningful for instantiation. --- clang/docs/ReleaseNotes.rst | 2 + clang/lib/Sema/SemaDeclCXX.cpp | 2 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 12 +++--- clang/test/SemaTemplate/GH55509.cpp | 38 +++++++++++++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1d0896f585fb4..c75ad0be8a8e6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -576,6 +576,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) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 08b3a423d1526..a8c3b28f8d185 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5751,14 +5751,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, RebuildTypeSourceInfoForDefaultSpecialMembers(); SetDeclDefaulted(Function, PatternDecl->getLocation()); } else { - NamedDecl *ND = Function; - DeclContext *DC = ND->getLexicalDeclContext(); + DeclContext *DC = Function->getLexicalDeclContext(); std::optional<ArrayRef<TemplateArgument>> Innermost; - if (auto *Primary = Function->getPrimaryTemplate(); - Primary && + bool NeedDCFromPrimaryTemplate = !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) && Function->getTemplateSpecializationKind() != - TSK_ExplicitSpecialization) { + TSK_ExplicitSpecialization && + !PatternDecl->getDependentSpecializationInfo(); + + if (auto *Primary = Function->getPrimaryTemplate(); + Primary && NeedDCFromPrimaryTemplate) { auto It = llvm::find_if(Primary->redecls(), [](const RedeclarableTemplateDecl *RTD) { return cast<FunctionTemplateDecl>(RTD) diff --git a/clang/test/SemaTemplate/GH55509.cpp b/clang/test/SemaTemplate/GH55509.cpp index 773a84305a0cd..f421e5a8fc237 100644 --- a/clang/test/SemaTemplate/GH55509.cpp +++ b/clang/test/SemaTemplate/GH55509.cpp @@ -110,3 +110,41 @@ namespace regression2 { } template void A<void>::f<long>(); } // namespace regression2 + +namespace GH139226 { + +struct FakeStream {}; + +template <typename T> +class BinaryTree; + +template <typename T> +FakeStream& operator<<(FakeStream& os, BinaryTree<T>& b); // #1 + +template <typename T> +FakeStream& operator>>(FakeStream& os, BinaryTree<T>& b) { + return os; +} + +template <typename T> +struct BinaryTree { + T* root{}; + // This template is described using a DependentSpecializationInfo, and its instantiations + // are tracked with TSK_ImplicitInstantiation kind. + // The primary template is declared at #1. + friend FakeStream& operator<< <T>(FakeStream& os, BinaryTree&) { + // expected-error@-1 {{friend function specialization cannot be defined}} + return os; + } + + friend FakeStream& operator>> <T>(FakeStream& os, BinaryTree&); +}; + +void foo() { + FakeStream fakeout; + BinaryTree<int> a{}; + fakeout << a; + fakeout >> a; +} + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits