diff options
author | John McCall <rjmccall@apple.com> | 2009-12-17 23:21:11 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-12-17 23:21:11 +0000 |
commit | e129d44aab6324aa2094d68730a7843c41a4e45f (patch) | |
tree | 3e3203a394da9d454e5b9fa6b0d91d5f247eccc5 | |
parent | 99860173af0b070f93558c26b78bb7ac07820370 (diff) |
Patch over yet more problems with friend declarations which were provoking
problems on LLVM-Code-Syntax. This proved remarkably easy to "fix" once
I settled on how I was going to approach it.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91633 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/AST/DeclCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 46 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/friend.cpp | 14 |
4 files changed, 49 insertions, 25 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 292a3ed630..986b81c0f8 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -874,7 +874,11 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, isa<CXXRecordDecl>(D) || isa<FunctionTemplateDecl>(D) || isa<ClassTemplateDecl>(D)); - assert(D->getFriendObjectKind()); + + // As a temporary hack, we permit template instantiation to point + // to the original declaration when instantiating members. + assert(D->getFriendObjectKind() || + (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind())); } #endif diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ac1b1ec0ee..c1d828fe45 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -691,6 +691,26 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.begin() != Previous.end()) PrevDecl = *Previous.begin(); + // If there is a previous declaration with the same name, check + // whether this is a valid redeclaration. + ClassTemplateDecl *PrevClassTemplate + = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); + + // We may have found the injected-class-name of a class template, + // class template partial specialization, or class template specialization. + // In these cases, grab the template that is being defined or specialized. + if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && + cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) { + PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext()); + PrevClassTemplate + = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate(); + if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) { + PrevClassTemplate + = cast<ClassTemplateSpecializationDecl>(PrevDecl) + ->getSpecializedTemplate(); + } + } + if (PrevDecl && TUK == TUK_Friend) { // C++ [namespace.memdef]p3: // [...] When looking for a prior declaration of a class or a function @@ -708,7 +728,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Declarations in outer scopes don't matter. However, the outermost // context we computed is the semantic context for our new // declaration. - PrevDecl = 0; + PrevDecl = PrevClassTemplate = 0; SemanticContext = OutermostContext; } @@ -717,30 +737,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // class template to the template in scope, because that would perform // checking of the template parameter lists that can't be performed // until the outer context is instantiated. - PrevDecl = 0; + PrevDecl = PrevClassTemplate = 0; } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) - PrevDecl = 0; - - // If there is a previous declaration with the same name, check - // whether this is a valid redeclaration. - ClassTemplateDecl *PrevClassTemplate - = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); - - // We may have found the injected-class-name of a class template, - // class template partial specialization, or class template specialization. - // In these cases, grab the template that is being defined or specialized. - if (!PrevClassTemplate && PrevDecl && isa<CXXRecordDecl>(PrevDecl) && - cast<CXXRecordDecl>(PrevDecl)->isInjectedClassName()) { - PrevDecl = cast<CXXRecordDecl>(PrevDecl->getDeclContext()); - PrevClassTemplate - = cast<CXXRecordDecl>(PrevDecl)->getDescribedClassTemplate(); - if (!PrevClassTemplate && isa<ClassTemplateSpecializationDecl>(PrevDecl)) { - PrevClassTemplate - = cast<ClassTemplateSpecializationDecl>(PrevDecl) - ->getSpecializedTemplate(); - } - } + PrevDecl = PrevClassTemplate = 0; if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 69982be84b..2ca4810055 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -396,7 +396,13 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // FIXME: We have a problem here, because the nested call to Visit(ND) // will inject the thing that the friend references into the current // owner, which is wrong. - Decl *NewND = Visit(ND); + Decl *NewND; + + // Hack to make this work almost well pending a rewrite. + if (ND->getDeclContext()->isRecord()) + NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs); + else + NewND = Visit(ND); if (!NewND) return 0; FU = cast<NamedDecl>(NewND); diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp index edb0dd53fe..dc13570718 100644 --- a/test/SemaCXX/friend.cpp +++ b/test/SemaCXX/friend.cpp @@ -15,3 +15,17 @@ namespace test0 { friend void ns::f(int a); }; } + +// Test derived from LLVM's Registry.h +namespace test1 { + template <class T> struct Outer { + void foo(T); + struct Inner { + friend void Outer::foo(T); + }; + }; + + void test() { + (void) Outer<int>::Inner(); + } +} |