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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102974 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e6cf059..f146c85 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3309,7 +3309,8 @@
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/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index e727cdb..14bd243 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -38,10 +38,16 @@
/// 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 @@
// 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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a81e5e9..8b851b2 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1970,8 +1970,8 @@
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 @@
CurContext = Function;
MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function);
+ getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
// If this is a constructor, instantiate the member initializers.
if (const CXXConstructorDecl *Ctor =