зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
e0047b13f0
Коммит
4423ac0282
|
@ -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.
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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++]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
Загрузка…
Ссылка в новой задаче