diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3591,11 +3591,28 @@ DeclContext *Owner = FunctionTemplate->getDeclContext(); if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); + FunctionDecl *FD = FunctionTemplate->getTemplatedDecl(); + // additional check for inline friend, + // ``` + // template int foo(F1 X); + // template struct A { + // template friend int foo(F1 X) { return A1; } + // }; + // template struct A<1>; + // int a = foo(1.0); + // ``` + const FunctionDecl *FDFriend; + if (FD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None && + FD->isDefined(FDFriend, /*CheckForPendingFriendDefinition*/ true) && + FDFriend->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None) { + FD = const_cast(FDFriend); + Owner = FD->getLexicalDeclContext(); + } MultiLevelTemplateArgumentList SubstArgs( FunctionTemplate, CanonicalDeducedArgumentList->asArray(), /*Final=*/false); Specialization = cast_or_null( - SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs)); + SubstDecl(FD, Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) return TDK_SubstitutionFailure; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4662,11 +4662,7 @@ ActiveInstType &ActiveInst = SemaRef.CodeSynthesisContexts.back(); if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { - if (FunctionTemplateDecl *FunTmpl - = dyn_cast(ActiveInst.Entity)) { - assert(FunTmpl->getTemplatedDecl() == Tmpl && - "Deduction from the wrong function template?"); - (void) FunTmpl; + if (isa(ActiveInst.Entity)) { SemaRef.InstantiatingSpecializations.erase( {ActiveInst.Entity->getCanonicalDecl(), ActiveInst.Kind}); atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); diff --git a/clang/test/SemaTemplate/template-friend-definition-in-template.cpp b/clang/test/SemaTemplate/template-friend-definition-in-template.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaTemplate/template-friend-definition-in-template.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +template int foo1(F1 X1); + +template struct A { + template friend int foo1(F2 X2) { + return A1; + } +}; + +template struct A<1>; +int main() { + foo1(1.0); +} + +template int foo2(F1 X1); + +template struct B { + template friend int foo2(F2 X2) { + return A1; + } +}; + +template struct B<1>; +template int foo2(float X1);