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

Reply via email to