summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-08-26 18:18:07 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-08-26 18:18:07 +0000
commit26a92d5852b2c6bf77efd26f6c0194c913f40285 (patch)
treeac752bec32ba60c72f8821d68345f8932005f713 /clang/lib/Sema
parentcb2380c9fa4be10aaee30d0a04fd9b354b922802 (diff)
downloadbcm5719-llvm-26a92d5852b2c6bf77efd26f6c0194c913f40285.tar.gz
bcm5719-llvm-26a92d5852b2c6bf77efd26f6c0194c913f40285.zip
Improve behavior in the case of stack exhaustion.
Summary: Clang performs various recursive operations (such as template instantiation), and may use non-trivial amounts of stack space in each recursive step (for instance, due to recursive AST walks). While we try to keep the stack space used by such steps to a minimum and we have explicit limits on the number of such steps we perform, it's impractical to guarantee that we won't blow out the stack on deeply recursive template instantiations on complex ASTs, even with only a moderately high instantiation depth limit. The user experience in these cases is generally terrible: we crash with no hint of what went wrong. Under this patch, we attempt to do better: * Detect when the stack is nearly exhausted, and produce a warning with a nice template instantiation backtrace, telling the user that we might run slowly or crash. * For cases where we're forced to trigger recursive template instantiation in arbitrarily-deeply-nested contexts, check whether we're nearly out of stack space and allocate a new stack (by spawning a new thread) after producing the warning. Reviewers: rnk, aaron.ballman Subscribers: mgorny, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66361 llvm-svn: 369940
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.cpp14
-rw-r--r--clang/lib/Sema/SemaExpr.cpp194
-rw-r--r--clang/lib/Sema/SemaInit.cpp7
-rw-r--r--clang/lib/Sema/SemaLookup.cpp56
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp1
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp14
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp6
-rw-r--r--clang/lib/Sema/SemaType.cpp22
9 files changed, 199 insertions, 121 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 17b414556ca..d4be3e92420 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
@@ -386,6 +387,19 @@ Sema::~Sema() {
assert(DelayedTypos.empty() && "Uncorrected typos!");
}
+void Sema::warnStackExhausted(SourceLocation Loc) {
+ // Only warn about this once.
+ if (!WarnedStackExhausted) {
+ Diag(Loc, diag::warn_stack_exhausted);
+ WarnedStackExhausted = true;
+ }
+}
+
+void Sema::runWithSufficientStackSpace(SourceLocation Loc,
+ llvm::function_ref<void()> Fn) {
+ clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn);
+}
+
/// makeUnavailableInSystemHeader - There is an error in the current
/// context. If we're still in a system header, and we can plausibly
/// make the relevant declaration unavailable instead of erroring, do
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ea72bcb259f..43e61d3429f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4832,8 +4832,10 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
LocalInstantiationScope Local(*this);
- Result = SubstInitializer(UninstExpr, MutiLevelArgList,
- /*DirectInit*/false);
+ runWithSufficientStackSpace(CallLoc, [&] {
+ Result = SubstInitializer(UninstExpr, MutiLevelArgList,
+ /*DirectInit*/false);
+ });
}
if (Result.isInvalid())
return true;
@@ -15175,6 +15177,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (IsRecursiveCall && OdrUse == OdrUseContext::Used)
OdrUse = OdrUseContext::FormallyOdrUsed;
+ // Trivial default constructors and destructors are never actually used.
+ // FIXME: What about other special members?
+ if (Func->isTrivial() && !Func->hasAttr<DLLExportAttr>() &&
+ OdrUse == OdrUseContext::Used) {
+ if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Func))
+ if (Constructor->isDefaultConstructor())
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ if (isa<CXXDestructorDecl>(Func))
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ }
+
// C++20 [expr.const]p12:
// A function [...] is needed for constant evaluation if it is [...] a
// constexpr function that is named by an expression that is potentially
@@ -15235,98 +15248,101 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
- Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
- if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
- if (Constructor->isDefaultConstructor()) {
- if (Constructor->isTrivial() &&
- !Constructor->hasAttr<DLLExportAttr>())
+ runWithSufficientStackSpace(Loc, [&] {
+ if (CXXConstructorDecl *Constructor =
+ dyn_cast<CXXConstructorDecl>(Func)) {
+ Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
+ if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
+ if (Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial() &&
+ !Constructor->hasAttr<DLLExportAttr>())
+ return;
+ DefineImplicitDefaultConstructor(Loc, Constructor);
+ } else if (Constructor->isCopyConstructor()) {
+ DefineImplicitCopyConstructor(Loc, Constructor);
+ } else if (Constructor->isMoveConstructor()) {
+ DefineImplicitMoveConstructor(Loc, Constructor);
+ }
+ } else if (Constructor->getInheritedConstructor()) {
+ DefineInheritingConstructor(Loc, Constructor);
+ }
+ } else if (CXXDestructorDecl *Destructor =
+ dyn_cast<CXXDestructorDecl>(Func)) {
+ Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
+ if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
+ if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
return;
- DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isCopyConstructor()) {
- DefineImplicitCopyConstructor(Loc, Constructor);
- } else if (Constructor->isMoveConstructor()) {
- DefineImplicitMoveConstructor(Loc, Constructor);
+ DefineImplicitDestructor(Loc, Destructor);
}
- } else if (Constructor->getInheritedConstructor()) {
- DefineInheritingConstructor(Loc, Constructor);
- }
- } else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(Func)) {
- Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
- if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
- if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
- return;
- DefineImplicitDestructor(Loc, Destructor);
+ if (Destructor->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, Destructor->getParent());
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
+ if (MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal) {
+ MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
+ if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
+ if (MethodDecl->isCopyAssignmentOperator())
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
+ else if (MethodDecl->isMoveAssignmentOperator())
+ DefineImplicitMoveAssignment(Loc, MethodDecl);
+ }
+ } else if (isa<CXXConversionDecl>(MethodDecl) &&
+ MethodDecl->getParent()->isLambda()) {
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
+ if (Conversion->isLambdaToBlockPointerConversion())
+ DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
+ else
+ DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
+ } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, MethodDecl->getParent());
}
- if (Destructor->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, Destructor->getParent());
- } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
- if (MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal) {
- MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
- if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
- if (MethodDecl->isCopyAssignmentOperator())
- DefineImplicitCopyAssignment(Loc, MethodDecl);
- else if (MethodDecl->isMoveAssignmentOperator())
- DefineImplicitMoveAssignment(Loc, MethodDecl);
- }
- } else if (isa<CXXConversionDecl>(MethodDecl) &&
- MethodDecl->getParent()->isLambda()) {
- CXXConversionDecl *Conversion =
- cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
- if (Conversion->isLambdaToBlockPointerConversion())
- DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
- else
- DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
- } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, MethodDecl->getParent());
- }
- // Implicit instantiation of function templates and member functions of
- // class templates.
- if (Func->isImplicitlyInstantiable()) {
- TemplateSpecializationKind TSK =
- Func->getTemplateSpecializationKindForInstantiation();
- SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
- bool FirstInstantiation = PointOfInstantiation.isInvalid();
- if (FirstInstantiation) {
- PointOfInstantiation = Loc;
- Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- } else if (TSK != TSK_ImplicitInstantiation) {
- // Use the point of use as the point of instantiation, instead of the
- // point of explicit instantiation (which we track as the actual point
- // of instantiation). This gives better backtraces in diagnostics.
- PointOfInstantiation = Loc;
- }
+ // Implicit instantiation of function templates and member functions of
+ // class templates.
+ if (Func->isImplicitlyInstantiable()) {
+ TemplateSpecializationKind TSK =
+ Func->getTemplateSpecializationKindForInstantiation();
+ SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
+ bool FirstInstantiation = PointOfInstantiation.isInvalid();
+ if (FirstInstantiation) {
+ PointOfInstantiation = Loc;
+ Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ } else if (TSK != TSK_ImplicitInstantiation) {
+ // Use the point of use as the point of instantiation, instead of the
+ // point of explicit instantiation (which we track as the actual point
+ // of instantiation). This gives better backtraces in diagnostics.
+ PointOfInstantiation = Loc;
+ }
- if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
- Func->isConstexpr()) {
- if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
- cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
- CodeSynthesisContexts.size())
- PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- else if (Func->isConstexpr())
- // Do not defer instantiations of constexpr functions, to avoid the
- // expression evaluator needing to call back into Sema if it sees a
- // call to such a function.
- InstantiateFunctionDefinition(PointOfInstantiation, Func);
- else {
- Func->setInstantiationIsPending(true);
- PendingInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- // Notify the consumer that a function was implicitly instantiated.
- Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
+ Func->isConstexpr()) {
+ if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
+ cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
+ CodeSynthesisContexts.size())
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ else if (Func->isConstexpr())
+ // Do not defer instantiations of constexpr functions, to avoid the
+ // expression evaluator needing to call back into Sema if it sees a
+ // call to such a function.
+ InstantiateFunctionDefinition(PointOfInstantiation, Func);
+ else {
+ Func->setInstantiationIsPending(true);
+ PendingInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ // Notify the consumer that a function was implicitly instantiated.
+ Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ }
+ }
+ } else {
+ // Walk redefinitions, as some of them may be instantiable.
+ for (auto i : Func->redecls()) {
+ if (!i->isUsed(false) && i->isImplicitlyInstantiable())
+ MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
}
- } else {
- // Walk redefinitions, as some of them may be instantiable.
- for (auto i : Func->redecls()) {
- if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkFunctionReferenced(Loc, i, MightBeOdrUse);
- }
- }
+ });
}
// If this is the first "real" use, act on that.
@@ -16493,7 +16509,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
if (UsableInConstantExpr) {
// Do not defer instantiations of variables that could be used in a
// constant expression.
- SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] {
+ SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ });
} else if (FirstInstantiation ||
isa<VarTemplateSpecializationDecl>(Var)) {
// FIXME: For a specialization of a variable template, we don't
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 3aa38b27c51..83c475a5f1c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6242,8 +6242,11 @@ PerformConstructorInitialization(Sema &S,
// the definition for completely trivial constructors.
assert(Constructor->getParent() && "No parent class for constructor.");
if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
- Constructor->isTrivial() && !Constructor->isUsed(false))
- S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ Constructor->isTrivial() && !Constructor->isUsed(false)) {
+ S.runWithSufficientStackSpace(Loc, [&] {
+ S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ });
+ }
}
ExprResult CurInit((Expr *)nullptr);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 8bae219f5ad..16fc822e5dd 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3088,8 +3088,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
- if (RD->needsImplicitDestructor())
- DeclareImplicitDestructor(RD);
+ if (RD->needsImplicitDestructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitDestructor(RD);
+ });
+ }
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
@@ -3112,21 +3115,36 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (SM == CXXDefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
- if (RD->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(RD);
+ if (RD->needsImplicitDefaultConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitDefaultConstructor(RD);
+ });
+ }
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
- if (RD->needsImplicitCopyConstructor())
- DeclareImplicitCopyConstructor(RD);
- if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor())
- DeclareImplicitMoveConstructor(RD);
+ if (RD->needsImplicitCopyConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitCopyConstructor(RD);
+ });
+ }
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitMoveConstructor(RD);
+ });
+ }
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- if (RD->needsImplicitCopyAssignment())
- DeclareImplicitCopyAssignment(RD);
- if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment())
- DeclareImplicitMoveAssignment(RD);
+ if (RD->needsImplicitCopyAssignment()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitCopyAssignment(RD);
+ });
+ }
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitMoveAssignment(RD);
+ });
+ }
}
if (ConstArg)
@@ -3283,12 +3301,14 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the implicit constructors have not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Class)) {
- if (Class->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(Class);
- if (Class->needsImplicitCopyConstructor())
- DeclareImplicitCopyConstructor(Class);
- if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
- DeclareImplicitMoveConstructor(Class);
+ runWithSufficientStackSpace(Class->getLocation(), [&] {
+ if (Class->needsImplicitDefaultConstructor())
+ DeclareImplicitDefaultConstructor(Class);
+ if (Class->needsImplicitCopyConstructor())
+ DeclareImplicitCopyConstructor(Class);
+ if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
+ DeclareImplicitMoveConstructor(Class);
+ });
}
CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class));
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index d230ec90d77..00771e22461 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index b55a232d26c..a75af62bf35 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4632,8 +4632,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
// We might need to deduce the return type by instantiating the definition
// of the operator() function.
- if (CallOp->getReturnType()->isUndeducedType())
- InstantiateFunctionDefinition(Loc, CallOp);
+ if (CallOp->getReturnType()->isUndeducedType()) {
+ runWithSufficientStackSpace(Loc, [&] {
+ InstantiateFunctionDefinition(Loc, CallOp);
+ });
+ }
}
if (CallOp->isInvalidDecl())
@@ -4654,8 +4657,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
return false;
}
- if (FD->getTemplateInstantiationPattern())
- InstantiateFunctionDefinition(Loc, FD);
+ if (FD->getTemplateInstantiationPattern()) {
+ runWithSufficientStackSpace(Loc, [&] {
+ InstantiateFunctionDefinition(Loc, FD);
+ });
+ }
bool StillUndeduced = FD->getReturnType()->isUndeducedType();
if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 973f564d305..d1ecefcc0c0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Stack.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
@@ -365,6 +366,11 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
if (!Ctx.isInstantiationRecord())
++NonInstantiationEntries;
+
+ // Check to see if we're low on stack space. We can't do anything about this
+ // from here, but we can at least warn the user.
+ if (isStackNearlyExhausted())
+ warnStackExhausted(Ctx.PointOfInstantiation);
}
void Sema::popCodeSynthesisContext() {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f340b68df64..6e4f9b99478 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3413,7 +3413,11 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
if (D->isInvalidDecl())
return nullptr;
- return Instantiator.Visit(D);
+ Decl *SubstD;
+ runWithSufficientStackSpace(D->getLocation(), [&] {
+ SubstD = Instantiator.Visit(D);
+ });
+ return SubstD;
}
/// Instantiates a nested template parameter list in the current
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 401874edf2f..4b16a09307c 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -7729,7 +7729,9 @@ void Sema::completeExprArrayBound(Expr *E) {
auto *Def = Var->getDefinition();
if (!Def) {
SourceLocation PointOfInstantiation = E->getExprLoc();
- InstantiateVariableDefinition(PointOfInstantiation, Var);
+ runWithSufficientStackSpace(PointOfInstantiation, [&] {
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
+ });
Def = Var->getDefinition();
// If we don't already have a point of instantiation, and we managed
@@ -8067,9 +8069,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
} else if (auto *ClassTemplateSpec =
dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
- Diagnosed = InstantiateClassTemplateSpecialization(
- Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
- /*Complain=*/Diagnoser);
+ runWithSufficientStackSpace(Loc, [&] {
+ Diagnosed = InstantiateClassTemplateSpecialization(
+ Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ });
Instantiated = true;
}
} else {
@@ -8080,10 +8084,12 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// This record was instantiated from a class within a template.
if (MSI->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization) {
- Diagnosed = InstantiateClass(Loc, RD, Pattern,
- getTemplateInstantiationArgs(RD),
- TSK_ImplicitInstantiation,
- /*Complain=*/Diagnoser);
+ runWithSufficientStackSpace(Loc, [&] {
+ Diagnosed = InstantiateClass(Loc, RD, Pattern,
+ getTemplateInstantiationArgs(RD),
+ TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ });
Instantiated = true;
}
}
OpenPOWER on IntegriCloud