diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-10 00:06:19 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-10 00:06:19 +0000 |
commit | 26dce44534602660ea9f4152bffc5436fc5fe3b2 (patch) | |
tree | 96930b1ee0febd8c91ad96a06bee73fdc67392e7 /lib | |
parent | 42745815fa4e90bfb07e581d2e5152b2c2db08ff (diff) |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/Sema.h | 55 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 34 |
3 files changed, 90 insertions, 1 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 83be895909..1acd6b2a85 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1664,6 +1664,61 @@ public: //===--------------------------------------------------------------------===// // 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 e9e2e3c2ac..b708598c62 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -351,7 +351,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // 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 71bba49af9..0990057df4 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 @@ Sema::InstantiateClassTemplateSpecialization( 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; |