From ab91ef1dbe524bba3c0147b11dfdd394153c783d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 8 Jul 2012 02:38:24 +0000 Subject: [PATCH] PR9793: Treat substitution as an instantiation step for the purpose of the -ftemplate-depth limit. There are various ways to get an infinite (or merely huge) stack of substitutions with no intervening instantiations. This is also consistent with gcc's behavior. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159907 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExpr.cpp | 2 + lib/Sema/SemaTemplate.cpp | 14 +++ lib/Sema/SemaTemplateInstantiate.cpp | 91 +++++++++---------- lib/Sema/SemaTemplateInstantiateDecl.cpp | 1 - .../instantiation-depth-defarg.cpp | 28 ++++++ .../instantiation-depth-subst-2.cpp | 9 ++ .../instantiation-depth-subst.cpp | 9 ++ 7 files changed, 104 insertions(+), 50 deletions(-) create mode 100644 test/SemaTemplate/instantiation-depth-defarg.cpp create mode 100644 test/SemaTemplate/instantiation-depth-subst-2.cpp create mode 100644 test/SemaTemplate/instantiation-depth-subst.cpp diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index cfc55e5715..6dbf704765 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3383,6 +3383,8 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, = ArgList.getInnermost(); InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first, Innermost.second); + if (Inst) + return ExprError(); ExprResult Result; { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 77695c199d..4605e01fa2 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1990,6 +1990,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TemplateArgLists.addOuterTemplateArguments(0, 0); InstantiatingTemplate Inst(*this, TemplateLoc, Template); + if (Inst) + return QualType(); CanonType = SubstType(Pattern->getUnderlyingType(), TemplateArgLists, AliasTemplate->getLocation(), AliasTemplate->getDeclName()); @@ -2550,6 +2552,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Template, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + if (Inst) + return 0; Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs, @@ -2599,6 +2603,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Template, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + if (Inst) + return ExprError(); Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); @@ -2648,6 +2654,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Template, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + if (Inst) + return TemplateName(); Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); // Substitute into the nested-name-specifier first, @@ -2781,6 +2789,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + if (Inst) + return true; TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); @@ -2913,6 +2923,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + if (Inst) + return true; TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); @@ -3144,6 +3156,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param, Converted.data(), Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); + if (Instantiating) + return true; // Check the default template argument. if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 8973916f37..7416d12301 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -156,11 +156,11 @@ bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { case ExceptionSpecInstantiation: case DefaultTemplateArgumentInstantiation: case DefaultFunctionArgumentInstantiation: - return true; - case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: case PriorTemplateArgumentSubstitution: + return true; + case DefaultTemplateArgumentChecking: return false; } @@ -252,8 +252,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SavedInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext) { - Invalid = CheckInstantiationDepth(PointOfInstantiation, - InstantiationRange); + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind = Kind; @@ -282,21 +281,19 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SavedInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext) { - Invalid = false; - - ActiveTemplateInstantiation Inst; - Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; - Inst.PointOfInstantiation = PointOfInstantiation; - Inst.Entity = reinterpret_cast(PartialSpec); - Inst.TemplateArgs = TemplateArgs; - Inst.NumTemplateArgs = NumTemplateArgs; - Inst.DeductionInfo = &DeductionInfo; - Inst.InstantiationRange = InstantiationRange; - SemaRef.InNonInstantiationSFINAEContext = false; - SemaRef.ActiveTemplateInstantiations.push_back(Inst); - - assert(!Inst.isInstantiationRecord()); - ++SemaRef.NonInstantiationEntries; + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast(PartialSpec); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.DeductionInfo = &DeductionInfo; + Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + } } Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, @@ -310,7 +307,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SemaRef.InNonInstantiationSFINAEContext) { Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); - if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind @@ -336,21 +332,19 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, SavedInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext) { - Invalid = false; - - ActiveTemplateInstantiation Inst; - Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; - Inst.PointOfInstantiation = PointOfInstantiation; - Inst.Template = Template; - Inst.Entity = reinterpret_cast(Param); - Inst.TemplateArgs = TemplateArgs; - Inst.NumTemplateArgs = NumTemplateArgs; - Inst.InstantiationRange = InstantiationRange; - SemaRef.InNonInstantiationSFINAEContext = false; - SemaRef.ActiveTemplateInstantiations.push_back(Inst); - - assert(!Inst.isInstantiationRecord()); - ++SemaRef.NonInstantiationEntries; + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Template = Template; + Inst.Entity = reinterpret_cast(Param); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + } } Sema::InstantiatingTemplate:: @@ -364,20 +358,19 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, SavedInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext) { - Invalid = false; - ActiveTemplateInstantiation Inst; - Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; - Inst.PointOfInstantiation = PointOfInstantiation; - Inst.Template = Template; - Inst.Entity = reinterpret_cast(Param); - Inst.TemplateArgs = TemplateArgs; - Inst.NumTemplateArgs = NumTemplateArgs; - Inst.InstantiationRange = InstantiationRange; - SemaRef.InNonInstantiationSFINAEContext = false; - SemaRef.ActiveTemplateInstantiations.push_back(Inst); - - assert(!Inst.isInstantiationRecord()); - ++SemaRef.NonInstantiationEntries; + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Template = Template; + Inst.Entity = reinterpret_cast(Param); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + } } Sema::InstantiatingTemplate:: diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index bbf8f50a3c..cce0b0d093 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2446,7 +2446,6 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, (void) FunTmpl; ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = reinterpret_cast(New); - --SemaRef.NonInstantiationEntries; } } diff --git a/test/SemaTemplate/instantiation-depth-defarg.cpp b/test/SemaTemplate/instantiation-depth-defarg.cpp new file mode 100644 index 0000000000..d66c71ba54 --- /dev/null +++ b/test/SemaTemplate/instantiation-depth-defarg.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 512 -ftemplate-backtrace-limit 4 %s + +template struct S { + typedef typename S::type type; + static int f(int n = S::f()); // \ +// expected-error{{recursive template instantiation exceeded maximum depth of 512}} \ +// expected-note 3 {{instantiation of default function argument}} \ +// expected-note {{skipping 509 contexts in backtrace}} \ +// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}} + +}; +template<> struct S<0> { + typedef int type; +}; + +// Incrementally instantiate up to S<2048>. +template struct S<256>; +template struct S<512>; +template struct S<768>; +template struct S<1024>; +template struct S<1280>; +template struct S<1536>; +template struct S<1792>; +template struct S<2048>; + +// Check that we actually bail out when we hit the instantiation depth limit for +// the default arguments. +void g() { S<2048>::f(); } // expected-note {{required here}} diff --git a/test/SemaTemplate/instantiation-depth-subst-2.cpp b/test/SemaTemplate/instantiation-depth-subst-2.cpp new file mode 100644 index 0000000000..a29d6b5a1b --- /dev/null +++ b/test/SemaTemplate/instantiation-depth-subst-2.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -verify %s -ftemplate-depth 2 + +template struct S { }; +// FIXME: We produce the same 'instantiation depth' error here many times +// (2^(depth+1) in total), due to additional lookups performed as part of +// error recovery in DiagnoseTwoPhaseOperatorLookup. +template S operator+(T, T); // expected-error 8{{}} expected-note 10{{}} +S<0> s; +int k = s + s; // expected-error {{invalid operands to binary expression}} diff --git a/test/SemaTemplate/instantiation-depth-subst.cpp b/test/SemaTemplate/instantiation-depth-subst.cpp new file mode 100644 index 0000000000..58e637411c --- /dev/null +++ b/test/SemaTemplate/instantiation-depth-subst.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s -ftemplate-depth 2 + +// PR9793 +template auto f(T t) -> decltype(f(t)); // \ +// expected-error {{recursive template instantiation exceeded maximum depth of 2}} \ +// expected-note 3 {{while substituting}} \ +// expected-note {{candidate}} + +int k = f(0); // expected-error {{no matching function for call to 'f'}} -- 2.40.0