Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -1452,8 +1452,9 @@ static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = nullptr); CanThrowResult canThrow(const Expr *E); - const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, - const FunctionProtoType *FPT); + const FunctionProtoType * + ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT, + FunctionDecl *OldDecl = nullptr); void UpdateExceptionSpec(FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI); bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range); @@ -7124,7 +7125,8 @@ getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, - const FunctionDecl *Pattern = nullptr); + const FunctionDecl *Pattern = nullptr, + FunctionTemplateDecl *PrevFTD = nullptr); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template @@ -7861,7 +7863,8 @@ const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, - FunctionDecl *Function); + FunctionDecl *Function, + FunctionDecl *OldFunction = nullptr); FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD, const TemplateArgumentList *Args, SourceLocation Loc); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -10009,6 +10009,7 @@ } if (Redeclaration) { + // NewFD and OldDecl represent declarations that need to be // merged. if (MergeFunctionDecl(NewFD, OldDecl, S, MergeTypeWithPrevious)) { Index: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ clang/lib/Sema/SemaExceptionSpec.cpp @@ -186,7 +186,8 @@ } const FunctionProtoType * -Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { +Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT, + FunctionDecl *OldDecl) { if (FPT->getExceptionSpecType() == EST_Unparsed) { Diag(Loc, diag::err_exception_spec_not_parsed); return nullptr; @@ -207,7 +208,7 @@ if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) EvaluateImplicitExceptionSpec(Loc, cast(SourceDecl)); else - InstantiateExceptionSpec(Loc, SourceDecl); + InstantiateExceptionSpec(Loc, SourceDecl, OldDecl); const FunctionProtoType *Proto = SourceDecl->getType()->castAs(); @@ -246,7 +247,8 @@ const FunctionProtoType *New, SourceLocation NewLoc, bool *MissingExceptionSpecification = nullptr, bool *MissingEmptyExceptionSpecification = nullptr, - bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); + bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false, + FunctionDecl *OldDecl = nullptr); /// Determine whether a function has an implicitly-generated exception /// specification. @@ -303,7 +305,7 @@ Old->getType()->getAs(), Old->getLocation(), New->getType()->getAs(), New->getLocation(), &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, - /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { + /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew, Old)) { // C++11 [except.spec]p4 [DR1492]: // If a declaration of a function has an implicit // exception-specification, other declarations of the function shall @@ -487,7 +489,8 @@ const FunctionProtoType *New, SourceLocation NewLoc, bool *MissingExceptionSpecification, bool *MissingEmptyExceptionSpecification, - bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) { + bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew, + FunctionDecl *OldDecl) { if (MissingExceptionSpecification) *MissingExceptionSpecification = false; @@ -497,7 +500,7 @@ Old = S.ResolveExceptionSpec(NewLoc, Old); if (!Old) return false; - New = S.ResolveExceptionSpec(NewLoc, New); + New = S.ResolveExceptionSpec(NewLoc, New, OldDecl); if (!New) return false; Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -51,11 +51,16 @@ /// instantiating the definition of the given declaration, \p D. This is /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. +/// +/// \param PrevFunTmpl If non-NULL, D is a pattern declaration of a function +/// template that hasn't yet been attached to the redeclaration chain of +/// PrevFunTmpl's pattern. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost, bool RelativeToPrimary, - const FunctionDecl *Pattern) { + const FunctionDecl *Pattern, + FunctionTemplateDecl *PrevFunTmpl) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -151,6 +156,16 @@ } else if (FunctionTemplateDecl *FunTmpl = Function->getDescribedFunctionTemplate()) { + if (PrevFunTmpl) { + // FunTmpl hasn't been linked into the same redecl chain as + // PrevFunTmpl yet, so we can't retreive it's injected template + // arguments just yet; use PrevFunTmpl's instead. + // + // Note that we don't need to verify that FunTmpl is the function + // template that is a redeclaration of PrevFunTmpl because only one + // function template decl can appear in this search. + FunTmpl = PrevFunTmpl; + } // Add the "injected" template arguments. Result.addOuterTemplateArguments(FunTmpl->getInjectedTemplateArgs()); } Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3575,7 +3575,8 @@ } void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, - FunctionDecl *Decl) { + FunctionDecl *Decl, + FunctionDecl *OldDecl) { const FunctionProtoType *Proto = Decl->getType()->castAs(); if (Proto->getExceptionSpecType() != EST_Uninstantiated) return; @@ -3601,8 +3602,9 @@ Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); + MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( + Decl, nullptr, /*RelativeToPrimary*/ true, nullptr, + !OldDecl ? nullptr : OldDecl->getDescribedFunctionTemplate()); FunctionDecl *Template = Proto->getExceptionSpecTemplate(); if (addInstantiatedParametersToScope(*this, Decl, Template, Scope, Index: clang/test/SemaCXX/friend-template-redecl.cpp =================================================================== --- /dev/null +++ clang/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); +}