Skip to content

Commit

Permalink
[AST] Refine the condition for element-dependent array fillers
Browse files Browse the repository at this point in the history
This patch fixes clang to not consider braced initializers for
aggregate elements of arrays to be potentially dependent on the
indices of the initialized elements. Resolves bug 18978:
initialize a large static array = clang oom?
https://bugs.llvm.org/show_bug.cgi?id=18978

Differential Revision: https://reviews.llvm.org/D43187

llvm-svn: 325120
  • Loading branch information
Ivan A. Kosarev committed Feb 14, 2018
1 parent 1768957 commit 01df519
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
25 changes: 23 additions & 2 deletions clang/lib/AST/ExprConstant.cpp
Expand Up @@ -48,6 +48,8 @@
#include <cstring>
#include <functional>

#define DEBUG_TYPE "exprconstant"

using namespace clang;
using llvm::APSInt;
using llvm::APFloat;
Expand Down Expand Up @@ -6780,6 +6782,22 @@ static bool EvaluateArray(const Expr *E, const LValue &This,
return ArrayExprEvaluator(Info, This, Result).Visit(E);
}

// Return true iff the given array filler may depend on the element index.
static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
// For now, just whitelist non-class value-initialization and initialization
// lists comprised of them.
if (isa<ImplicitValueInitExpr>(FillerExpr))
return false;
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(FillerExpr)) {
for (unsigned I = 0, E = ILE->getNumInits(); I != E; ++I) {
if (MaybeElementDependentArrayFiller(ILE->getInit(I)))
return true;
}
return false;
}
return true;
}

bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType());
if (!CAT)
Expand Down Expand Up @@ -6809,10 +6827,13 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr;

// If the initializer might depend on the array index, run it for each
// array element. For now, just whitelist non-class value-initialization.
if (NumEltsToInit != NumElts && !isa<ImplicitValueInitExpr>(FillerExpr))
// array element.
if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr))
NumEltsToInit = NumElts;

DEBUG(llvm::dbgs() << "The number of elements to initialize: " <<
NumEltsToInit << ".\n");

Result = APValue(APValue::UninitArray(), NumEltsToInit, NumElts);

// If the array was previously zero-initialized, preserve the
Expand Down
9 changes: 9 additions & 0 deletions clang/test/SemaCXX/large-array-init.cpp
@@ -0,0 +1,9 @@
// RUN: %clang_cc1 -S -o %t.ll -mllvm -debug-only=exprconstant %s 2>&1 | \
// RUN: FileCheck %s

struct S { int i; };

static struct S arr[100000000] = {{ 0 }};
// CHECK: The number of elements to initialize: 1.

struct S *foo() { return arr; }

0 comments on commit 01df519

Please sign in to comment.