Limit the template instantiation depth to some user-configurable value
(default: 99). Beyond this limit, produce an error and consider the
current template instantiation a failure.

The stack we're building to track the instantiations will, eventually,
be used to produce instantiation backtraces from diagnostics within
template instantiation. However, we're not quite there yet.

This adds a new Clang driver option -ftemplate-depth=NNN, which should
eventually be generated from the GCC command-line operation
-ftemplate-depth-NNN (note the '-' rather than the '='!). I did not
make the driver changes to do this mapping.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66513 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 83be895..1acd6b2 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1664,6 +1664,61 @@
   //===--------------------------------------------------------------------===//
   // C++ Template Instantiation
   //
+
+  /// \brief A template instantiation that is currently in progress.
+  struct ActiveTemplateInstantiation {
+    /// \brief The point of instantiation within the source code.
+    SourceLocation PointOfInstantiation;
+
+    /// \brief The entity that is being instantiated.
+    ClassTemplateSpecializationDecl *Entity;
+
+    /// \brief The source range that covers the construct that cause
+    /// the instantiation, e.g., the template-id that causes a class
+    /// template instantiation.
+    SourceRange InstantiationRange;
+  };
+
+  /// \brief List of active template instantiations.
+  ///
+  /// This vector is treated as a stack. As one template instantiation
+  /// requires another template instantiation, additional
+  /// instantiations are pushed onto the stack up to a
+  /// user-configurable limit LangOptions::InstantiationDepth.
+  llvm::SmallVector<ActiveTemplateInstantiation, 16> 
+    ActiveTemplateInstantiations;
+
+  /// \brief A stack object to be created when performing template
+  /// instantiation.
+  ///
+  /// Construction of an object of type \c InstantiatingTemplate
+  /// pushes the current instantiation onto the stack of active
+  /// instantiations. If the size of this stack exceeds the maximum
+  /// number of recursive template instantiations, construction
+  /// produces an error and evaluates true.
+  ///
+  /// Destruction of this object will pop the named instantiation off
+  /// the stack.
+  struct InstantiatingTemplate {
+    InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+                          ClassTemplateSpecializationDecl *Entity,
+                          SourceRange InstantiationRange = SourceRange());
+    ~InstantiatingTemplate();
+
+    /// \brief Determines whether we have exceeded the maximum
+    /// recursive template instantiations.
+    operator bool() const { return Invalid; }
+
+  private:
+    Sema &SemaRef;
+    bool Invalid;
+
+    InstantiatingTemplate(const InstantiatingTemplate&); // not implemented
+
+    InstantiatingTemplate& 
+    operator=(const InstantiatingTemplate&); // not implemented
+  };
+
   QualType InstantiateType(QualType T, const TemplateArgument *TemplateArgs,
                            unsigned NumTemplateArgs,
                            SourceLocation Loc, DeclarationName Entity);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e9e2e3c..b708598 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -351,7 +351,7 @@
   //   The class-name in a base-specifier shall not be an incompletely
   //   defined class.
   if (RequireCompleteType(BaseLoc, BaseType, diag::err_incomplete_base_class,
-                             SpecifierRange))
+                          SpecifierRange))
     return 0;
 
   // If the base class is polymorphic, the new one is, too.
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 71bba49..0990057 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -21,6 +21,35 @@
 
 using namespace clang;
 
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+                      ClassTemplateSpecializationDecl *Entity,
+                      SourceRange InstantiationRange)
+  :  SemaRef(SemaRef) {
+  if (SemaRef.ActiveTemplateInstantiations.size() 
+        > SemaRef.getLangOptions().InstantiationDepth) {
+    SemaRef.Diag(PointOfInstantiation, 
+                 diag::err_template_recursion_depth_exceeded)
+      << SemaRef.getLangOptions().InstantiationDepth
+      << InstantiationRange;
+    SemaRef.Diag(PointOfInstantiation, diag::note_template_recursion_depth)
+      << SemaRef.getLangOptions().InstantiationDepth;
+    Invalid = true;
+  } else {
+    ActiveTemplateInstantiation Inst;
+    Inst.PointOfInstantiation = PointOfInstantiation;
+    Inst.Entity = Entity;
+    Inst.InstantiationRange = InstantiationRange;
+    SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+    Invalid = false;
+  }
+}
+
+Sema::InstantiatingTemplate::~InstantiatingTemplate() {
+  if (!Invalid)
+    SemaRef.ActiveTemplateInstantiations.pop_back();
+}
+
 //===----------------------------------------------------------------------===/
 // Template Instantiation for Types
 //===----------------------------------------------------------------------===/
@@ -526,6 +555,11 @@
 
   bool Invalid = false;
   
+  InstantiatingTemplate Inst(*this, ClassTemplateSpec->getLocation(),
+                             ClassTemplateSpec);
+  if (Inst)
+    return true;
+
   // Enter the scope of this instantiation. We don't use
   // PushDeclContext because we don't have a scope.
   DeclContext *PreviousContext = CurContext;