[clang] [Clang] Stop changing DC when instantiating dependent friend specializations (PR #139436)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Sat May 10 22:21:39 PDT 2025
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 <zyn7109 at 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 at -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;
+}
+
+}
More information about the cfe-commits
mailing list