From 1bd7a944600083821afe54ca9366863d40f6990a Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 3 May 2010 23:29:10 +0000 Subject: [PATCH] When computing the template arguments for the instantiation of a friend function template, be sure to adjust the computed template argument lists based on the location of the definition of the function template: it's possible that the definition we're instantiating with and the template declaration that we found when creating the specialization are in different contexts, which meant that we would end up using the wrong template arguments for instantiation. Fixes PR7013; all Boost.DynamicBitset tests now pass. llvm-svn: 102974 --- clang/lib/Sema/Sema.h | 3 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 14 +++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 +- clang/test/SemaTemplate/friend-template.cpp | 65 +++++++++++++++++++ 4 files changed, 81 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index e6cf0599b426..f146c8578721 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -3309,7 +3309,8 @@ public: MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = 0, - bool RelativeToPrimary = false); + bool RelativeToPrimary = false, + const FunctionDecl *Pattern = 0); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index e727cdbc9e87..14bd24320104 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -38,10 +38,16 @@ using namespace clang; /// arguments relative to the primary template, even when we're /// dealing with a specialization. This is only relevant for function /// template specializations. +/// +/// \param Pattern If non-NULL, indicates the pattern from which we will be +/// instantiating the definition of the given declaration, \p D. This is +/// used to determine the proper set of template instantiation arguments for +/// friend function template specializations. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost, - bool RelativeToPrimary) { + bool RelativeToPrimary, + const FunctionDecl *Pattern) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -89,9 +95,11 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, // If this is a friend declaration and it declares an entity at // namespace scope, take arguments from its lexical parent - // instead of its semantic parent. + // instead of its semantic parent, unless of course the pattern we're + // instantiating actually comes from the file's context! if (Function->getFriendObjectKind() && - Function->getDeclContext()->isFileContext()) { + Function->getDeclContext()->isFileContext() && + (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { Ctx = Function->getLexicalDeclContext(); RelativeToPrimary = false; continue; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a81e5e95f895..8b851b21eacd 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1970,8 +1970,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) - return; - + return; + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. @@ -2003,7 +2003,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, CurContext = Function; MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function); + getTemplateInstantiationArgs(Function, 0, false, PatternDecl); // If this is a constructor, instantiate the member initializers. if (const CXXConstructorDecl *Ctor = diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp index 4b60a3db05d6..1d62804f68ac 100644 --- a/clang/test/SemaTemplate/friend-template.cpp +++ b/clang/test/SemaTemplate/friend-template.cpp @@ -142,3 +142,68 @@ namespace FriendTemplateDefinition { f(x, i5); } } + +namespace PR7013a { + template struct X0 + { + typedef int type; + }; + template struct X1 + { + }; + template struct X2 + { + typename T::type e; + }; + namespace N + { + template > struct X3 + { + template friend void op(X2& , B); + }; + template void op(X2& , B) + { + X2 s; + } + } + int n() + { + X2 > ngs; + N::X3<> b; + op(ngs, b); + return 0; + } +} + +namespace PR7013b { + template struct X0 + { + typedef int type; + }; + template struct X1 + { + }; + template struct X2 + { + typename T::type e; + }; + namespace N + { + template > struct X3 + { + template friend void op(X2& , B); + }; + template void op(X2& , B) + { + X2 s; + } + } + int n() + { + X2 > ngs; + N::X3<> b; + op(ngs, b); + return 0; + } + +}