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