From: John McCall Date: Thu, 17 Dec 2009 23:21:11 +0000 (+0000) Subject: Patch over yet more problems with friend declarations which were provoking X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e129d44aab6324aa2094d68730a7843c41a4e45f;p=clang 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 --- 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(D) || isa(D) || isa(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(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(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(PrevDecl) && + cast(PrevDecl)->isInjectedClassName()) { + PrevDecl = cast(PrevDecl->getDeclContext()); + PrevClassTemplate + = cast(PrevDecl)->getDescribedClassTemplate(); + if (!PrevClassTemplate && isa(PrevDecl)) { + PrevClassTemplate + = cast(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(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(PrevDecl) && - cast(PrevDecl)->isInjectedClassName()) { - PrevDecl = cast(PrevDecl->getDeclContext()); - PrevClassTemplate - = cast(PrevDecl)->getDescribedClassTemplate(); - if (!PrevClassTemplate && isa(PrevDecl)) { - PrevClassTemplate - = cast(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(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 struct Outer { + void foo(T); + struct Inner { + friend void Outer::foo(T); + }; + }; + + void test() { + (void) Outer::Inner(); + } +}