Collect multiple levels of template arguments into a new type,
MultiLevelTemplateArgumentList. This is a baby step toward
instantiating member templates; no intended functionality change yet.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80380 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 52eb89e..d710544 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -18,6 +18,7 @@
 #include "IdentifierResolver.h"
 #include "CXXFieldCollector.h"
 #include "SemaOverload.h"
+#include "SemaTemplate.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/Decl.h"
@@ -2626,7 +2627,7 @@
   // C++ Template Instantiation
   //
 
-  const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D);
+  MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D);
 
   /// \brief A template instantiation that is currently in progress.
   struct ActiveTemplateInstantiation {
diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h
new file mode 100644
index 0000000..3f814e4
--- /dev/null
+++ b/lib/Sema/SemaTemplate.h
@@ -0,0 +1,80 @@
+//===------- SemaTemplate.h - C++ Templates ---------------------*- C++ -*-===/
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+//  This file provides types used in the semantic analysis of C++ templates.
+//
+//===----------------------------------------------------------------------===/
+#ifndef LLVM_CLANG_SEMA_TEMPLATE_H
+#define LLVM_CLANG_SEMA_TEMPLATE_H
+
+#include "clang/AST/DeclTemplate.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+
+namespace clang {
+  /// \brief Data structure that captures multiple levels of template argument
+  /// lists for use in template instantiation.
+  ///
+  /// Multiple levels of template arguments occur when instantiating the 
+  /// definitions of member templates. For example:
+  ///
+  /// \code
+  /// template<typename T>
+  /// struct X {
+  ///   template<T Value>
+  ///   struct Y {
+  ///     void f();
+  ///   };
+  /// };
+  /// \endcode
+  ///
+  /// When instantiating X<int>::Y<17>::f, the multi-level template argument
+  /// list will contain a template argument list (int) at depth 0 and a
+  /// template argument list (17) at depth 1.
+  struct MultiLevelTemplateArgumentList {
+    /// \brief The template argument lists, stored from the innermost template
+    /// argument list (first) to the outermost template argument list (last)
+    llvm::SmallVector<const TemplateArgumentList *, 4> TemplateArgumentLists;
+    
+  public:
+    /// \brief Construct an empty set of template argument lists.
+    MultiLevelTemplateArgumentList() { }
+    
+    /// \brief Construct a single-level template argument list.
+    MultiLevelTemplateArgumentList(const TemplateArgumentList *TemplateArgs) {
+      TemplateArgumentLists.push_back(TemplateArgs);
+    }
+    
+    /// \brief Determine the number of levels in this template argument
+    /// list.
+    unsigned getNumLevels() const { return TemplateArgumentLists.size(); }
+    
+    /// \brief Retrieve the template argument at a given depth and index.
+    const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
+      assert(Depth < TemplateArgumentLists.size());
+      assert(Index < TemplateArgumentLists[getNumLevels() - Depth]->size());
+      return TemplateArgumentLists[getNumLevels() - Depth]->get(Index);
+    }
+    
+    /// \brief Add a new outermost level to the multi-level template argument 
+    /// list.
+    void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) {
+      TemplateArgumentLists.push_back(TemplateArgs);
+    }
+    
+    // Implicit conversion to a single template argument list, to facilitate a
+    // gradual transition to MultiLevelTemplateArgumentLists.
+    operator const TemplateArgumentList &() const {
+      assert(getNumLevels() == 1 && 
+             "Conversion only works with a single level of template arguments");
+      return *TemplateArgumentLists.front();
+    }
+  };
+}
+
+#endif // LLVM_CLANG_SEMA_TEMPLATE_H
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 4642251..b330ae9 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -28,30 +28,39 @@
 
 /// \brief Retrieve the template argument list that should be used to
 /// instantiate the given declaration.
-const TemplateArgumentList &
+MultiLevelTemplateArgumentList
 Sema::getTemplateInstantiationArgs(NamedDecl *D) {
-  // Template arguments for a class template specialization.
-  if (ClassTemplateSpecializationDecl *Spec 
-        = dyn_cast<ClassTemplateSpecializationDecl>(D))
-    return Spec->getTemplateInstantiationArgs();
-
-  // Template arguments for a function template specialization.
-  if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
-    if (const TemplateArgumentList *TemplateArgs
-          = Function->getTemplateSpecializationArgs())
-      return *TemplateArgs;
+  // Accumulate the set of template argument lists in this structure.
+  MultiLevelTemplateArgumentList Result;
+  
+  DeclContext *Ctx = dyn_cast<DeclContext>(D);
+  if (!Ctx)
+    Ctx = D->getDeclContext();
+  
+  for (; !Ctx->isFileContext(); Ctx = Ctx->getParent()) {
+    // Add template arguments from a class template instantiation.
+    if (ClassTemplateSpecializationDecl *Spec 
+          = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+      // We're done when we hit an explicit specialization.
+      if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization)
+        break;
       
-  // Template arguments for a member of a class template specialization.
-  DeclContext *EnclosingTemplateCtx = D->getDeclContext();
-  while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) {
-    assert(!EnclosingTemplateCtx->isFileContext() &&
-           "Tried to get the instantiation arguments of a non-template");
-    EnclosingTemplateCtx = EnclosingTemplateCtx->getParent();
+      Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
+      continue;
+    } 
+    
+    // Add template arguments from a function template specialization.
+    if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
+      // FIXME: Check whether this is an explicit specialization.
+      if (const TemplateArgumentList *TemplateArgs
+            = Function->getTemplateSpecializationArgs())
+        Result.addOuterTemplateArguments(TemplateArgs);
+      
+      continue;
+    }
   }
-
-  ClassTemplateSpecializationDecl *EnclosingTemplate 
-    = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx);
-  return EnclosingTemplate->getTemplateInstantiationArgs();
+  
+  return Result;
 }
 
 Sema::InstantiatingTemplate::
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
index 959e5c1..dc79012 100644
--- a/test/SemaTemplate/instantiate-member-template.cpp
+++ b/test/SemaTemplate/instantiate-member-template.cpp
@@ -20,3 +20,4 @@
   X0<void> xv;
   double *&dpr2 = xv.f1(ip, dp);
 }
+