Skip to content

Commit 1756fbc

Browse files
committed
[Clang] Stop looking for DC from dependent friend specializations
Since 346077a, 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.
1 parent fcb4bda commit 1756fbc

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,8 @@ Bug Fixes in This Version
576576
``#include`` directive. (#GH138094)
577577
- Fixed a crash during constant evaluation involving invalid lambda captures
578578
(#GH138832)
579+
- Fixed a crash when instantiating an invalid dependent friend template specialization.
580+
(#GH139052)
579581

580582
Bug Fixes to Compiler Builtins
581583
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18740,7 +18740,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
1874018740
// a template-id, the function name is not unqualified because these is
1874118741
// no name. While the wording requires some reading in-between the
1874218742
// lines, GCC, MSVC, and EDG all consider a friend function
18743-
// specialization definitions // to be de facto explicit specialization
18743+
// specialization definitions to be de facto explicit specialization
1874418744
// and diagnose them as such.
1874518745
} else if (isTemplateId) {
1874618746
Diag(NameInfo.getBeginLoc(), diag::err_friend_specialization_def);

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5751,14 +5751,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
57515751
RebuildTypeSourceInfoForDefaultSpecialMembers();
57525752
SetDeclDefaulted(Function, PatternDecl->getLocation());
57535753
} else {
5754-
NamedDecl *ND = Function;
5755-
DeclContext *DC = ND->getLexicalDeclContext();
5754+
DeclContext *DC = Function->getLexicalDeclContext();
57565755
std::optional<ArrayRef<TemplateArgument>> Innermost;
5757-
if (auto *Primary = Function->getPrimaryTemplate();
5758-
Primary &&
5756+
bool NeedDCFromPrimaryTemplate =
57595757
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
57605758
Function->getTemplateSpecializationKind() !=
5761-
TSK_ExplicitSpecialization) {
5759+
TSK_ExplicitSpecialization &&
5760+
!PatternDecl->getDependentSpecializationInfo();
5761+
5762+
if (auto *Primary = Function->getPrimaryTemplate();
5763+
Primary && NeedDCFromPrimaryTemplate) {
57625764
auto It = llvm::find_if(Primary->redecls(),
57635765
[](const RedeclarableTemplateDecl *RTD) {
57645766
return cast<FunctionTemplateDecl>(RTD)

clang/test/SemaTemplate/GH55509.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,41 @@ namespace regression2 {
110110
}
111111
template void A<void>::f<long>();
112112
} // namespace regression2
113+
114+
namespace GH139226 {
115+
116+
struct FakeStream {};
117+
118+
template <typename T>
119+
class BinaryTree;
120+
121+
template <typename T>
122+
FakeStream& operator<<(FakeStream& os, BinaryTree<T>& b); // #1
123+
124+
template <typename T>
125+
FakeStream& operator>>(FakeStream& os, BinaryTree<T>& b) {
126+
return os;
127+
}
128+
129+
template <typename T>
130+
struct BinaryTree {
131+
T* root{};
132+
// This template is described using a DependentSpecializationInfo, and its instantiations
133+
// are tracked with TSK_ImplicitInstantiation kind.
134+
// The primary template is declared at #1.
135+
friend FakeStream& operator<< <T>(FakeStream& os, BinaryTree&) {
136+
// expected-error@-1 {{friend function specialization cannot be defined}}
137+
return os;
138+
}
139+
140+
friend FakeStream& operator>> <T>(FakeStream& os, BinaryTree&);
141+
};
142+
143+
void foo() {
144+
FakeStream fakeout;
145+
BinaryTree<int> a{};
146+
fakeout << a;
147+
fakeout >> a;
148+
}
149+
150+
}

0 commit comments

Comments
 (0)