From d7e29e114d20da5b83e0cb7bc29ec717a7458cb1 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 26 Mar 2010 02:05:14 +0000 Subject: [PATCH] Properly instantiate and link in friend function templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99596 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaAccess.cpp | 2 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 43 ++++++++++++++------- test/CXX/temp/temp.decls/temp.friend/p1.cpp | 13 +++++++ 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index a92989696e..4cfd99d5c5 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -319,7 +319,7 @@ static Sema::AccessResult MatchesFriend(Sema &S, if (Friend == FTD->getCanonicalDecl()) return Sema::AR_accessible; - if (MightInstantiateTo(S, FTD, Friend)) + if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) return Sema::AR_dependent; return Sema::AR_inaccessible; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index cbd9086dfb..d929b5a370 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -904,8 +904,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // Check whether there is already a function template specialization for // this declaration. FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); + + bool isFriend; + if (FunctionTemplate) + isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); + else + isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + void *InsertPos = 0; - if (FunctionTemplate && !TemplateParams) { + if (!isFriend && FunctionTemplate && !TemplateParams) { llvm::FoldingSetNodeID ID; FunctionTemplateSpecializationInfo::Profile(ID, TemplateArgs.getInnermost().getFlatArgumentList(), @@ -933,14 +940,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return 0; QualType T = TInfo->getType(); + NestedNameSpecifier *Qualifier = D->getQualifier(); + if (Qualifier) { + Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, + D->getQualifierRange(), + TemplateArgs); + if (!Qualifier) return 0; + } + // If we're instantiating a local function declaration, put the result // in the owner; otherwise we need to find the instantiated context. DeclContext *DC; if (D->getDeclContext()->isFunctionOrMethod()) DC = Owner; - else + else if (isFriend && Qualifier) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(D->getQualifierRange()); + DC = SemaRef.computeDeclContext(SS); + if (!DC) return 0; + } else { DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), TemplateArgs); + } FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), @@ -948,9 +970,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); - // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Function)) - return 0; + if (Qualifier) + Function->setQualifierInfo(Qualifier, D->getQualifierRange()); Function->setLexicalDeclContext(Owner); @@ -974,7 +995,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // which means substituting int for T, but leaving "f" as a friend function // template. // Build the function template itself. - FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner, + FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC, Function->getLocation(), Function->getDeclName(), TemplateParams, Function); @@ -1016,9 +1037,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // If the original function was part of a friend declaration, // inherit its namespace state and add it to the owner. - NamedDecl *FromFriendD - = TemplateParams? cast(D->getDescribedFunctionTemplate()) : D; - if (FromFriendD->getFriendObjectKind()) { + if (isFriend) { NamedDecl *ToFriendD = 0; NamedDecl *PrevDecl; if (TemplateParams) { @@ -1029,11 +1048,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrevDecl = Function->getPreviousDeclaration(); } ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL); - if (!Owner->isDependentContext() && !PrevDecl) - DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false); - - if (!TemplateParams) - Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false); } return Function; diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp index 39818028bb..0e41e5f832 100644 --- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp +++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp @@ -178,3 +178,16 @@ namespace test7 { }; template class D; } + +namespace test8 { + template class A { + static int x; + template friend void foo(); + }; + template class A; + + template void foo() { + A::x = 0; + } + template void foo(); +} -- 2.40.0