Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
38 changes: 38 additions & 0 deletions clang/test/SemaTemplate/GH55509.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

}