From: Argyrios Kyrtzidis Date: Thu, 21 Apr 2011 00:27:41 +0000 (+0000) Subject: For X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4423ac0282acb8ba801eb05b38712438dc0c1e3e;p=clang For double data[20000000] = {0}; we would blow out the memory by creating 20M Exprs to fill out the initializer. To fix this, if the initializer list initializes an array with more elements than there are initializers in the list, have InitListExpr store a single 'ArrayFiller' expression that specifies an expression to be used for value initialization of the rest of the elements. Fixes rdar://9275920. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129896 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 6b616c28b3..7420408226 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -3178,9 +3178,14 @@ class InitListExpr : public Expr { /// written in the source code. InitListExpr *SyntacticForm; - /// If this initializer list initializes a union, specifies which - /// field within the union will be initialized. - FieldDecl *UnionFieldInit; + /// \brief Either: + /// If this initializer list initializes an array with more elements than + /// there are initializers in the list, specifies an expression to be used + /// for value initialization of the rest of the elements. + /// Or + /// If this initializer list initializes a union, specifies which + /// field within the union will be initialized. + llvm::PointerUnion ArrayFillerOrUnionFieldInit; /// Whether this initializer list originally had a GNU array-range /// designator in it. This is a temporary marker used by CodeGen. @@ -3235,14 +3240,28 @@ public: /// accommodate the new entry. Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr); + /// \brief If this initializer list initializes an array with more elements + /// than there are initializers in the list, specifies an expression to be + /// used for value initialization of the rest of the elements. + Expr *getArrayFiller() { + return ArrayFillerOrUnionFieldInit.dyn_cast(); + } + void setArrayFiller(Expr *filler) { + ArrayFillerOrUnionFieldInit = filler; + } + /// \brief If this initializes a union, specifies which field in the /// union to initialize. /// /// Typically, this field is the first named field within the /// union. However, a designated initializer can specify the /// initialization of a different field within the union. - FieldDecl *getInitializedFieldInUnion() { return UnionFieldInit; } - void setInitializedFieldInUnion(FieldDecl *FD) { UnionFieldInit = FD; } + FieldDecl *getInitializedFieldInUnion() { + return ArrayFillerOrUnionFieldInit.dyn_cast(); + } + void setInitializedFieldInUnion(FieldDecl *FD) { + ArrayFillerOrUnionFieldInit = FD; + } // Explicit InitListExpr's originate from source code (and have valid source // locations). Implicit InitListExpr's are created by the semantic analyzer. @@ -3293,6 +3312,9 @@ public: const_reverse_iterator rbegin() const { return InitExprs.rbegin(); } reverse_iterator rend() { return InitExprs.rend(); } const_reverse_iterator rend() const { return InitExprs.rend(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; }; /// @brief Represents a C99 designated initializer expression. diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1f6c2fab1b..9b978e8439 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1254,7 +1254,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, false), InitExprs(C, numInits), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), - UnionFieldInit(0), HadArrayRangeDesignator(false) + HadArrayRangeDesignator(false) { for (unsigned I = 0; I != numInits; ++I) { if (initExprs[I]->isTypeDependent()) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 14a1222cad..e738f0dc90 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -319,6 +319,8 @@ public: bool VisitInitListExpr(InitListExpr *E) { for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) if (Visit(E->getInit(i))) return true; + if (Expr *filler = E->getArrayFiller()) + return Visit(filler); return false; } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 6fb9987ecd..5b3c0905e5 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -641,6 +641,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { if (i < NumInitElements) EmitInitializationToLValue(E->getInit(i), LV, ElementType); + else if (Expr *filler = E->getArrayFiller()) + EmitInitializationToLValue(filler, LV, ElementType); else EmitNullInitializationToLValue(LV, ElementType); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 8e26b206eb..338fb03b8a 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -667,8 +667,16 @@ public: // Initialize remaining array elements. // FIXME: This doesn't handle member pointers correctly! + llvm::Constant *fillC; + if (Expr *filler = ILE->getArrayFiller()) + fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF); + else + fillC = llvm::Constant::getNullValue(ElemTy); + if (!fillC) + return 0; + RewriteType |= (fillC->getType() != ElemTy); for (; i < NumElements; ++i) - Elts.push_back(llvm::Constant::getNullValue(ElemTy)); + Elts.push_back(fillC); if (RewriteType) { // FIXME: Try to avoid packing the array diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 84ab23e584..307db14b58 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -405,14 +405,23 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, // Do nothing } else if (Init < NumInits) { ILE->setInit(Init, ElementInit.takeAs()); - } else if (InitSeq.getKind() + } else { + // For arrays, just set the expression used for value-initialization + // of the rest of elements and exit. + if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) { + ILE->setArrayFiller(ElementInit.takeAs()); + return; + } + + if (InitSeq.getKind() == InitializationSequence::ConstructorInitialization) { - // Value-initialization requires a constructor call, so - // extend the initializer list to include the constructor - // call and make a note that we'll need to take another pass - // through the initializer list. - ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs()); - RequiresSecondPass = true; + // Value-initialization requires a constructor call, so + // extend the initializer list to include the constructor + // call and make a note that we'll need to take another pass + // through the initializer list. + ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs()); + RequiresSecondPass = true; + } } } else if (InitListExpr *InnerILE = dyn_cast(ILE->getInit(Init))) diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 79b0e48f13..19e0e6463b 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -690,8 +690,11 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { E->setSyntacticForm(cast_or_null(Reader.ReadSubStmt())); E->setLBraceLoc(ReadSourceLocation(Record, Idx)); E->setRBraceLoc(ReadSourceLocation(Record, Idx)); - E->setInitializedFieldInUnion( - cast_or_null(Reader.GetDecl(Record[Idx++]))); + if (Record[Idx++]) // isArrayFiller + E->ArrayFillerOrUnionFieldInit = Reader.ReadSubExpr(); + else + E->ArrayFillerOrUnionFieldInit + = cast_or_null(Reader.GetDecl(Record[Idx++])); E->sawArrayRangeDesignator(Record[Idx++]); } diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 6238983f80..2a48273415 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -673,7 +673,12 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) { Writer.AddStmt(E->getSyntacticForm()); Writer.AddSourceLocation(E->getLBraceLoc(), Record); Writer.AddSourceLocation(E->getRBraceLoc(), Record); - Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record); + bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is(); + Record.push_back(isArrayFiller); + if (isArrayFiller) + Writer.AddStmt(E->getArrayFiller()); + else + Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record); Record.push_back(E->hadArrayRangeDesignator()); Code = serialization::EXPR_INIT_LIST; } diff --git a/test/Index/initializer-memory.cpp b/test/Index/initializer-memory.cpp new file mode 100644 index 0000000000..d0f531fdd2 --- /dev/null +++ b/test/Index/initializer-memory.cpp @@ -0,0 +1,14 @@ +// RUN: c-index-test -test-load-source-memory-usage none %s 2>&1 | FileCheck %s + +// rdar://9275920 - We would create millions of Exprs to fill out the initializer. + +double data[1000000] = {0}; + +struct S { + S(int); + S(); +}; + +S data2[1000000] = {0}; + +// CHECK: TOTAL = {{.*}} (0.{{.*}} MBytes)