summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/Expr.h32
-rw-r--r--clang/lib/AST/Expr.cpp2
-rw-r--r--clang/lib/AST/ExprConstant.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp10
-rw-r--r--clang/lib/Sema/SemaInit.cpp23
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp7
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--clang/test/Index/initializer-memory.cpp14
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)
OpenPOWER on IntegriCloud