diff options
-rw-r--r-- | clang/include/clang/AST/Expr.h | 32 | ||||
-rw-r--r-- | clang/lib/AST/Expr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 23 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderStmt.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterStmt.cpp | 7 | ||||
-rw-r--r-- | clang/test/Index/initializer-memory.cpp | 14 |
9 files changed, 82 insertions, 17 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 6b616c28b39..74204082264 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/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<Expr *, FieldDecl *> 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<Expr *>(); + } + 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<FieldDecl *>(); + } + 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/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 1f6c2fab1b8..9b978e84395 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/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/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 14a1222cad5..e738f0dc908 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/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/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 6fb9987ecd7..5b3c0905e54 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/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/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 8e26b206ebf..338fb03b8a0 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/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/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 84ab23e584c..307db14b588 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -405,14 +405,23 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, // Do nothing } else if (Init < NumInits) { ILE->setInit(Init, ElementInit.takeAs<Expr>()); - } 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<Expr>()); + 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<Expr>()); - 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<Expr>()); + RequiresSecondPass = true; + } } } else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init))) diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 79b0e48f139..19e0e6463b7 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -690,8 +690,11 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt())); E->setLBraceLoc(ReadSourceLocation(Record, Idx)); E->setRBraceLoc(ReadSourceLocation(Record, Idx)); - E->setInitializedFieldInUnion( - cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]))); + if (Record[Idx++]) // isArrayFiller + E->ArrayFillerOrUnionFieldInit = Reader.ReadSubExpr(); + else + E->ArrayFillerOrUnionFieldInit + = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])); E->sawArrayRangeDesignator(Record[Idx++]); } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 6238983f80f..2a482734154 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/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<Expr*>(); + 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/clang/test/Index/initializer-memory.cpp b/clang/test/Index/initializer-memory.cpp new file mode 100644 index 00000000000..d0f531fdd2f --- /dev/null +++ b/clang/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) |