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. llvm-svn: 66513
This commit is contained in:
parent
99d2835099
commit
fcd5db3bfa
|
@ -515,7 +515,10 @@ static llvm::cl::list<std::string>
|
|||
TargetFeatures("mattr", llvm::cl::CommaSeparated,
|
||||
llvm::cl::desc("Target specific attributes (-mattr=help for details)"));
|
||||
|
||||
|
||||
static llvm::cl::opt<unsigned>
|
||||
TemplateDepth("ftemplate-depth", llvm::cl::init(99),
|
||||
llvm::cl::desc("Maximum depth of recursive template "
|
||||
"instantiation"));
|
||||
|
||||
// FIXME: add:
|
||||
// -fdollars-in-identifiers
|
||||
|
@ -642,6 +645,8 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
|
|||
|
||||
Options.MathErrno = MathErrno;
|
||||
|
||||
Options.InstantiationDepth = TemplateDepth;
|
||||
|
||||
// Override the default runtime if the user requested it.
|
||||
if (NeXTRuntime)
|
||||
Options.NeXTRuntime = 1;
|
||||
|
|
|
@ -640,6 +640,11 @@ DIAG(err_template_spec_redecl_global_scope, ERROR,
|
|||
"class template specialization of %0 must occur in at global scope")
|
||||
|
||||
// C++ Template Instantiation
|
||||
DIAG(err_template_recursion_depth_exceeded, ERROR,
|
||||
"recursive template instantiation exceeded maximum depth of %0")
|
||||
DIAG(note_template_recursion_depth, NOTE,
|
||||
"use -ftemplate-depth=N to increase recursive template "
|
||||
"instantiation depth")
|
||||
DIAG(err_template_implicit_instantiate_undefined, ERROR,
|
||||
"implicit instantiation of undefined template %0")
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ private:
|
|||
// this enum as unsigned because MSVC insists on making enums
|
||||
// signed. Set/Query this value using accessors.
|
||||
public:
|
||||
unsigned InstantiationDepth; // Maximum template instantiation depth.
|
||||
|
||||
enum GCMode { NonGC, GCOnly, HybridGC };
|
||||
|
||||
|
@ -80,6 +81,8 @@ public:
|
|||
Blocks = 0;
|
||||
EmitAllDecls = 0;
|
||||
MathErrno = 1;
|
||||
|
||||
InstantiationDepth = 99;
|
||||
}
|
||||
|
||||
GCMode getGCMode() const { return (GCMode) GC; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: clang -fsyntax-only -ftemplate-depth=5 -verify %s
|
||||
|
||||
template<typename T> struct X : X<T*> { }; // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
|
||||
// expected-note{{use -ftemplate-depth=N to increase recursive template instantiation depth}}
|
||||
|
||||
void test() {
|
||||
(void)sizeof(X<int>);
|
||||
}
|
Loading…
Reference in New Issue