Skip to content

Commit 866f1cd

Browse files
authored
[Clang] Stop changing DC when instantiating dependent friend specializations (llvm#139436)
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 anything meaningful for instantiation. Fixes llvm#139052
1 parent 036d637 commit 866f1cd

File tree

5 files changed

+49
-5
lines changed

5 files changed

+49
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,8 @@ Bug Fixes in This Version
586586
``#include`` directive. (#GH138094)
587587
- Fixed a crash during constant evaluation involving invalid lambda captures
588588
(#GH138832)
589+
- Fixed a crash when instantiating an invalid dependent friend template specialization.
590+
(#GH139052)
589591
- Fixed a crash with an invalid member function parameter list with a default
590592
argument which contains a pragma. (#GH113722)
591593
- Fixed assertion failures when generating name lookup table in modules. (#GH61065, #GH134739)

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/SemaTemplate.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9383,7 +9383,10 @@ bool Sema::CheckFunctionTemplateSpecialization(
93839383

93849384
// Mark the prior declaration as an explicit specialization, so that later
93859385
// clients know that this is an explicit specialization.
9386-
if (!isFriend) {
9386+
// A dependent friend specialization which has a definition should be treated
9387+
// as explicit specialization, despite being invalid.
9388+
if (FunctionDecl *InstFrom = FD->getInstantiatedFromMemberFunction();
9389+
!isFriend || (InstFrom && InstFrom->getDependentSpecializationInfo())) {
93879390
// Since explicit specializations do not inherit '=delete' from their
93889391
// primary function template - check if the 'specialization' that was
93899392
// implicitly generated (during template argument deduction for partial
@@ -11370,7 +11373,12 @@ class ExplicitSpecializationVisibilityChecker {
1137011373
template<typename SpecDecl>
1137111374
void checkImpl(SpecDecl *Spec) {
1137211375
bool IsHiddenExplicitSpecialization = false;
11373-
if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
11376+
TemplateSpecializationKind SpecKind = Spec->getTemplateSpecializationKind();
11377+
// Some invalid friend declarations are written as specializations but are
11378+
// instantiated implicitly.
11379+
if constexpr (std::is_same_v<SpecDecl, FunctionDecl>)
11380+
SpecKind = Spec->getTemplateSpecializationKindForInstantiation();
11381+
if (SpecKind == TSK_ExplicitSpecialization) {
1137411382
IsHiddenExplicitSpecialization = Spec->getMemberSpecializationInfo()
1137511383
? !CheckMemberSpecialization(Spec)
1137611384
: !CheckExplicitSpecialization(Spec);

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5756,8 +5756,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
57565756
RebuildTypeSourceInfoForDefaultSpecialMembers();
57575757
SetDeclDefaulted(Function, PatternDecl->getLocation());
57585758
} else {
5759-
NamedDecl *ND = Function;
5760-
DeclContext *DC = ND->getLexicalDeclContext();
5759+
DeclContext *DC = Function->getLexicalDeclContext();
57615760
std::optional<ArrayRef<TemplateArgument>> Innermost;
57625761
if (auto *Primary = Function->getPrimaryTemplate();
57635762
Primary &&

clang/test/SemaTemplate/GH55509.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,38 @@ 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);
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+
friend FakeStream& operator<< <T>(FakeStream& os, BinaryTree&) {
133+
// expected-error@-1 {{friend function specialization cannot be defined}}
134+
return os;
135+
}
136+
137+
friend FakeStream& operator>> <T>(FakeStream& os, BinaryTree&);
138+
};
139+
140+
void foo() {
141+
FakeStream fakeout;
142+
BinaryTree<int> a{};
143+
fakeout << a;
144+
fakeout >> a;
145+
}
146+
147+
}

0 commit comments

Comments
 (0)