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
This commit is contained in:
Douglas Gregor 2010-05-03 23:29:10 +00:00
parent 81bfca7bde
commit 1bd7a94460
4 changed files with 81 additions and 7 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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 =

View File

@ -142,3 +142,68 @@ namespace FriendTemplateDefinition {
f(x, i5);
}
}
namespace PR7013a {
template<class > struct X0
{
typedef int type;
};
template<typename > struct X1
{
};
template<typename , typename T> struct X2
{
typename T::type e;
};
namespace N
{
template <typename = int, typename = X1<int> > struct X3
{
template <typename T1, typename T2, typename B> friend void op(X2<T1, T2>& , B);
};
template <typename Ch, typename Tr, typename B> void op(X2<Ch, Tr>& , B)
{
X2<int, Tr> s;
}
}
int n()
{
X2<int, X0<int> > ngs;
N::X3<> b;
op(ngs, b);
return 0;
}
}
namespace PR7013b {
template<class > struct X0
{
typedef int type;
};
template<typename > struct X1
{
};
template<typename , typename T> struct X2
{
typename T::type e;
};
namespace N
{
template <typename = X1<int> > struct X3
{
template <typename T1, typename T2, typename B> friend void op(X2<T1, T2>& , B);
};
template <typename Ch, typename Tr, typename B> void op(X2<Ch, Tr>& , B)
{
X2<int, Tr> s;
}
}
int n()
{
X2<int, X0<int> > ngs;
N::X3<> b;
op(ngs, b);
return 0;
}
}