aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp14
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp6
-rw-r--r--test/SemaTemplate/friend-template.cpp65
4 files changed, 81 insertions, 7 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e6cf0599b4..f146c85787 100644
--- a/lib/Sema/Sema.h
+++ b/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/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index e727cdbc9e..14bd243201 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a81e5e95f8..8b851b21ea 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/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/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index 4b60a3db05..1d62804f68 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -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;
+ }
+
+}