When evaluating a VarDecl as a constant or determining whether it is
an integral constant expression, maintain a cache of the value and the
is-an-ICE flag within the VarDecl itself. This eliminates
exponential-time behavior of the Fibonacci template metaprogram.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72428 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 20fe39d..6c62071 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -89,6 +89,15 @@
return getType();
}
+void VarDecl::setInit(ASTContext &C, Expr *I) {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
+ Eval->~EvaluatedStmt();
+ C.Deallocate(Eval);
+ }
+
+ Init = I;
+ }
+
bool VarDecl::isExternC(ASTContext &Context) const {
if (!Context.getLangOptions().CPlusPlus)
return (getDeclContext()->isTranslationUnit() &&
@@ -287,8 +296,13 @@
void VarDecl::Destroy(ASTContext& C) {
Expr *Init = getInit();
- if (Init)
+ if (Init) {
Init->Destroy(C);
+ if (EvaluatedStmt *Eval = this->Init.dyn_cast<EvaluatedStmt *>()) {
+ Eval->~EvaluatedStmt();
+ C.Deallocate(Eval);
+ }
+ }
this->~VarDecl();
C.Deallocate((void *)this);
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 6711faf..aca5efe 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1210,8 +1210,21 @@
// type initialized by an ICE can be used in ICEs.
if (const VarDecl *Dcl =
dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
- if (const Expr *Init = Dcl->getInit())
- return CheckICE(Init, Ctx);
+ if (Dcl->isInitKnownICE()) {
+ // We have already checked whether this subexpression is an
+ // integral constant expression.
+ if (Dcl->isInitICE())
+ return NoDiag();
+ else
+ return ICEDiag(2, E->getLocStart());
+ }
+
+ if (const Expr *Init = Dcl->getInit()) {
+ ICEDiag Result = CheckICE(Init, Ctx);
+ // Cache the result of the ICE test.
+ Dcl->setInitKnownICE(Ctx, Result.Val == 0);
+ return Result;
+ }
}
}
return ICEDiag(2, E->getLocStart());
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 34b0187..7651884 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -700,8 +700,17 @@
// In C, they can also be folded, although they are not ICEs.
if (E->getType().getCVRQualifiers() == QualType::Const) {
if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
- if (const Expr *Init = D->getInit())
- return Visit(const_cast<Expr*>(Init));
+ if (APValue *V = D->getEvaluatedValue())
+ return Success(V->getInt(), E);
+ if (const Expr *Init = D->getInit()) {
+ if (Visit(const_cast<Expr*>(Init))) {
+ // Cache the evaluated value in the variable declaration.
+ D->setEvaluatedValue(Info.Ctx, Result);
+ return true;
+ }
+
+ return false;
+ }
}
}
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 20024f5..5c22e28 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -140,14 +140,14 @@
if (inDeclGroup()) {
VarDecl* VD = cast<VarDecl>(*DGI);
- return VD->Init;
+ return *VD->getInitAddress();
}
assert (inDecl());
if (VarDecl* VD = dyn_cast<VarDecl>(decl)) {
assert (VD->Init);
- return VD->Init;
+ return *VD->getInitAddress();
}
EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl);
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 7d4c634..adf0d11 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -342,7 +342,7 @@
cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
if (Record[Idx++])
- VD->setInit(Reader.ReadDeclExpr());
+ VD->setInit(*Reader.getContext(), Reader.ReadDeclExpr());
}
void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 22bdc79..4149fa4 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2581,7 +2581,7 @@
// };
// Attach the initializer
- VDecl->setInit(Init);
+ VDecl->setInit(Context, Init);
// C++ [class.mem]p4:
// A member-declarator can contain a constant-initializer only
@@ -2644,7 +2644,7 @@
}
// Attach the initializer to the decl.
- VDecl->setInit(Init);
+ VDecl->setInit(Context, Init);
// If the previous declaration of VDecl was a tentative definition,
// remove it from the set of tentative definitions.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index feb9456..ebe3406 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1776,7 +1776,7 @@
Expr **Exprs, unsigned NumExprs) {
Expr *Temp = CXXConstructExpr::Create(Context, VD, DeclInitType, Constructor,
false, Exprs, NumExprs);
- VD->setInit(Temp);
+ VD->setInit(Context, Temp);
}
/// AddCXXDirectInitializerToDecl - This action is called immediately after