Index: cfe/trunk/include/clang/AST/DeclTemplate.h =================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h +++ cfe/trunk/include/clang/AST/DeclTemplate.h @@ -1093,6 +1093,9 @@ /// template. ArrayRef getInjectedTemplateArgs(); + /// Merge our RedeclarableTemplateDecl::Common with \param Prev. + void mergePrevDecl(FunctionTemplateDecl *Prev); + /// Create a function template node. static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, Index: cfe/trunk/lib/AST/DeclTemplate.cpp =================================================================== --- cfe/trunk/lib/AST/DeclTemplate.cpp +++ cfe/trunk/lib/AST/DeclTemplate.cpp @@ -300,6 +300,42 @@ return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size()); } +void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { + using Base = RedeclarableTemplateDecl; + + // If we haven't created a common pointer yet, then it can just be created + // with the usual method. + if (!Base::Common) + return; + + Common *ThisCommon = static_cast(Base::Common); + Common *PrevCommon = nullptr; + SmallVector PreviousDecls; + for (; Prev; Prev = Prev->getPreviousDecl()) { + if (Prev->Base::Common) { + PrevCommon = static_cast(Prev->Base::Common); + break; + } + PreviousDecls.push_back(Prev); + } + + // If the previous redecl chain hasn't created a common pointer yet, then just + // use this common pointer. + if (!PrevCommon) { + for (auto *D : PreviousDecls) + D->Base::Common = ThisCommon; + return; + } + + // Ensure we don't leak any important state. + assert(ThisCommon->Specializations.size() == 0 && + !ThisCommon->InstantiatedFromMember.getPointer() && + !ThisCommon->InstantiatedFromMember.getInt() && + "Can't merge incompatible declarations!"); + + Base::Common = PrevCommon; +} + //===----------------------------------------------------------------------===// // ClassTemplateDecl Implementation //===----------------------------------------------------------------------===// Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -10022,11 +10022,17 @@ if (FunctionTemplateDecl *OldTemplateDecl = dyn_cast(OldDecl)) { auto *OldFD = OldTemplateDecl->getTemplatedDecl(); - NewFD->setPreviousDeclaration(OldFD); - adjustDeclContextForDeclaratorDecl(NewFD, OldFD); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); + + // The call to MergeFunctionDecl above may have created some state in + // NewTemplateDecl that needs to be merged with OldTemplateDecl before we + // can add it as a redeclaration. + NewTemplateDecl->mergePrevDecl(OldTemplateDecl); + + NewFD->setPreviousDeclaration(OldFD); + adjustDeclContextForDeclaratorDecl(NewFD, OldFD); if (NewFD->isCXXClassMember()) { NewFD->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); Index: cfe/trunk/test/SemaCXX/friend-template-redecl.cpp =================================================================== --- cfe/trunk/test/SemaCXX/friend-template-redecl.cpp +++ cfe/trunk/test/SemaCXX/friend-template-redecl.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++17 -verify -emit-llvm-only %s + +// expected-no-diagnostics + +template void bar(const T &t) { foo(t); } + +template +struct HasFriend { + template + friend void foo(const HasFriend &m) noexcept(false); +}; + +template +void foo(const HasFriend &m) noexcept(false) {} + +void f() { + HasFriend x; + foo(x); + bar(x); +}