diff options
author | John McCall <rjmccall@apple.com> | 2010-03-26 02:05:14 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-03-26 02:05:14 +0000 |
commit | d7e29e114d20da5b83e0cb7bc29ec717a7458cb1 (patch) | |
tree | 287b1f33feef5513ef4990b8492e347f6e9d4880 | |
parent | f16c76c2e61cca3889ecef23fbb475a9cebad4e3 (diff) |
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
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 43 | ||||
-rw-r--r-- | 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<NamedDecl>(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<int>; } + +namespace test8 { + template <class N> class A { + static int x; + template <class T> friend void foo(); + }; + template class A<int>; + + template <class T> void foo() { + A<int>::x = 0; + } + template void foo<int>(); +} |