From 30837102a2ef32218c5d95d372b9ab3561733b6c Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 26 Mar 2010 23:10:15 +0000 Subject: [PATCH] Put function templates instantiated from friend declarations in the correct lexical context. This is required for ADL to work properly; fixes PR6716. llvm-svn: 99665 --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 21 +++++++++++++------ .../basic.lookup/basic.lookup.argdep/p4.cpp | 12 +++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index e795f0ad1bcd..59c9819751c8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -840,16 +840,18 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { assert(InstTemplate && "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); + bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None); + // Link the instantiation back to the pattern *unless* this is a // non-definition friend declaration. if (!InstTemplate->getInstantiatedFromMemberTemplate() && - !(InstTemplate->getFriendObjectKind() && - !D->getTemplatedDecl()->isThisDeclarationADefinition())) + !(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition())) InstTemplate->setInstantiatedFromMemberTemplate(D); - // Add non-friends into the owner. - if (!InstTemplate->getFriendObjectKind()) + // Make declarations visible in the appropriate context. + if (!isFriend) Owner->addDecl(InstTemplate); + return InstTemplate; } @@ -973,7 +975,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (Qualifier) Function->setQualifierInfo(Qualifier, D->getQualifierRange()); - Function->setLexicalDeclContext(Owner); + DeclContext *LexicalDC = Owner; + if (!isFriend && D->isOutOfLine()) { + assert(D->getDeclContext()->isFileContext()); + LexicalDC = D->getDeclContext(); + } + + Function->setLexicalDeclContext(LexicalDC); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) @@ -1000,7 +1008,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Function->getDeclName(), TemplateParams, Function); Function->setDescribedFunctionTemplate(FunctionTemplate); - FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + + FunctionTemplate->setLexicalDeclContext(LexicalDC); if (isFriend && D->isThisDeclarationADefinition()) { // TODO: should we remember this connection regardless of whether diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp index b59e6ca320e0..df3429ef31c7 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp @@ -40,3 +40,15 @@ namespace Test { D::D() + D::D(); // expected-error {{ invalid operands to binary expression ('D::D' and 'D::D') }} } } + +// PR6716 +namespace test1 { + template class A { + template friend void foo(A &, U); // expected-note {{not viable: 1st argument ('A const') would lose const qualifier}} + }; + + void test() { + const A a; + foo(a, 10); // expected-error {{no matching function for call to 'foo'}} + } +}