Ping.
Re-based patch to trunk r222712.
http://reviews.llvm.org/D5789
Files:
include/clang/AST/Expr.h
lib/AST/Expr.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprCXX.cpp
lib/CodeGen/CGExprConstant.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/CodeGen/Inputs/stdio.h
test/CodeGen/partial-reinitialization1.c
test/CodeGen/partial-reinitialization2.c
test/PCH/designated-init.c.h
test/Sema/designated-initializers.c
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -3768,6 +3768,14 @@
/// - the semantic form, if this is in syntactic form.
llvm::PointerIntPair<InitListExpr *, 1, bool> AltForm;
+ // In cases like:
+ // struct P { char x[6]; } pvar = { "foo" };
+ // struct PP { struct P p; } ppvar = { .p = pvar, .p.x[1] = 'b' };
+ //
+ // In the InitListExpr corresponding to "ppvar.p", PrevInitExpr will hold the
+ // Expr corresponding to the variable pvar.
+ Expr *PrevInitExpr;
+
/// \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
@@ -3783,7 +3791,7 @@
/// \brief Build an empty initializer list.
explicit InitListExpr(EmptyShell Empty)
- : Expr(InitListExprClass, Empty) { }
+ : Expr(InitListExprClass, Empty), PrevInitExpr(nullptr) { }
unsigned getNumInits() const { return InitExprs.size(); }
@@ -3833,6 +3841,14 @@
/// accommodate the new entry.
Expr *updateInit(const ASTContext &C, unsigned Init, Expr *expr);
+ Expr *getPrevInitExpr() const { return PrevInitExpr; }
+ void setPrevInitExpr(Expr *newExpr) { PrevInitExpr = newExpr; }
+
+ /// \brief If this initializer only partially initializes the declarator,
+ /// the background initializer will initialize the rest. The background
+ /// initializer is assumed to be evaluatable at compile time.
+ void partialMergeFrom(const ASTContext &C, Expr *BackgroundExpr);
+
/// \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.
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1871,7 +1871,8 @@
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
InitExprs(C, initExprs.size()),
- LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(nullptr, true)
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(nullptr, true),
+ PrevInitExpr(nullptr)
{
sawArrayRangeDesignator(false);
for (unsigned I = 0; I != initExprs.size(); ++I) {
@@ -1909,6 +1910,95 @@
return Result;
}
+void InitListExpr::partialMergeFrom(const ASTContext &C, Expr *BackgroundExpr) {
+ assert(!hasArrayFiller() && "Filler already exists!");
+
+ BackgroundExpr = BackgroundExpr->IgnoreParenImpCasts();
+ if (CompoundLiteralExpr *CLE =
+ dyn_cast<CompoundLiteralExpr>(BackgroundExpr))
+ BackgroundExpr = CLE->getInitializer()->IgnoreParenImpCasts();
+
+ // A string literal or an obj-c encode expression gets decomposed into
+ // individual characters.
+ if (isa<StringLiteral>(BackgroundExpr) ||
+ isa<ObjCEncodeExpr>(BackgroundExpr)) {
+ const ArrayType *AT = C.getAsArrayType(getType());
+ assert(AT && "expecting array type");
+
+ QualType CharTy = AT->getElementType();
+ QualType PromotedCharTy = (CharTy->isPromotableIntegerType() ?
+ C.getPromotedIntegerType(CharTy) : CharTy);
+ unsigned CharWidth = C.getTypeSize(PromotedCharTy);
+
+ const StringLiteral *SL = dyn_cast<StringLiteral>(BackgroundExpr);
+ const ObjCEncodeExpr *OEE = dyn_cast<ObjCEncodeExpr>(BackgroundExpr);
+ std::string OEE_Str;
+ if (OEE)
+ C.getObjCEncodingForType(OEE->getEncodedType(), OEE_Str);
+
+ uint64_t StrLen = SL ? SL->getLength() : OEE_Str.size();
+ const llvm::APInt &ArraySize = cast<ConstantArrayType>(AT)->getSize();
+ if (ArraySize.ult(StrLen))
+ StrLen = ArraySize.getZExtValue();
+
+ if (StrLen > InitExprs.size())
+ InitExprs.resize(C, StrLen, nullptr);
+
+ for (unsigned i = 0; i != StrLen; ++i) {
+ if (getInit(i))
+ continue;
+
+ llvm::APInt Element(CharWidth, SL ? SL->getCodeUnit(i) : OEE_Str[i]);
+ Expr *ElementExpr = IntegerLiteral::Create(C, Element, PromotedCharTy,
+ BackgroundExpr->getExprLoc());
+ if (CharTy != PromotedCharTy)
+ ElementExpr = ImplicitCastExpr::Create(C, CharTy, CK_IntegralCast,
+ ElementExpr, nullptr, VK_RValue);
+ setInit(i, ElementExpr);
+ }
+
+ if (ArraySize.ugt(StrLen))
+ setArrayFiller(new (C) ImplicitValueInitExpr(CharTy));
+
+ return;
+ }
+
+ assert(isa<InitListExpr>(BackgroundExpr) &&
+ "cannot break down background initializer!");
+ InitListExpr *BackgroundILE = cast<InitListExpr>(BackgroundExpr);
+ if (BackgroundILE->getNumInits() > InitExprs.size())
+ InitExprs.resize(C, BackgroundILE->getNumInits(), nullptr);
+
+ for (unsigned i = 0; i != getNumInits(); ++i) {
+ if (i >= BackgroundILE->getNumInits() || !BackgroundILE->getInit(i))
+ // Nothing to merge from.
+ continue;
+
+ if (!getInit(i)) {
+ setInit(i, BackgroundILE->getInit(i));
+ continue;
+ }
+
+ // If this is not an aggregate type, we are done. The current initializer
+ // takes effect; the background initializer is overwritten.
+ Expr *ChildExpr = getInit(i);
+ if (!ChildExpr->getType()->isAggregateType())
+ continue;
+
+ assert(isa<InitListExpr>(ChildExpr) && "expecting an init list expr");
+
+ InitListExpr *ChildILE = cast<InitListExpr>(ChildExpr);
+ ChildILE->partialMergeFrom(C, BackgroundILE->getInit(i));
+
+ // Only look at the first initialization of a union
+ if (getType()->isUnionType())
+ break;
+ }
+
+ if (BackgroundILE->hasArrayFiller())
+ setArrayFiller(BackgroundILE->getArrayFiller());
+}
+
void InitListExpr::setArrayFiller(Expr *filler) {
assert(!hasArrayFiller() && "Filler already set!");
ArrayFillerOrUnionFieldInit = filler;
@@ -2759,11 +2849,15 @@
}
case InitListExprClass: {
const InitListExpr *ILE = cast<InitListExpr>(this);
+ if (ILE->getPrevInitExpr())
+ return ILE->getPrevInitExpr()->isConstantInitializer(Ctx, false, Culprit);
+
if (ILE->getType()->isArrayType()) {
unsigned numInits = ILE->getNumInits();
for (unsigned i = 0; i < numInits; i++) {
- if (!ILE->getInit(i)->isConstantInitializer(Ctx, false, Culprit))
- return false;
+ if (const Expr *Init = ILE->getInit(i))
+ if (!Init->isConstantInitializer(Ctx, false, Culprit))
+ return false;
}
return true;
}
@@ -2782,6 +2876,8 @@
if (ElementNo < ILE->getNumInits()) {
const Expr *Elt = ILE->getInit(ElementNo++);
+ if (!Elt)
+ continue;
if (Field->isBitField()) {
// Bitfields have to evaluate to an integer.
llvm::APSInt ResultTmp;
@@ -2973,6 +3069,9 @@
if (const Expr *E = cast<InitListExpr>(this)->getArrayFiller())
if (E->HasSideEffects(Ctx))
return true;
+ if (const Expr *E = cast<InitListExpr>(this)->getPrevInitExpr())
+ if (E->HasSideEffects(Ctx))
+ return true;
break;
case GenericSelectionExprClass:
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -5292,7 +5292,7 @@
LValue Subobject = This;
- bool HaveInit = ElementNo < E->getNumInits();
+ bool HaveInit = ElementNo < E->getNumInits() && E->getInit(ElementNo);
// FIXME: Diagnostics here should point to the end of the initializer
// list, not the start.
@@ -5752,7 +5752,8 @@
Subobject.addArray(Info, E, CAT);
for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
const Expr *Init =
- Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
+ (Index < E->getNumInits() && E->getInit(Index)) ?
+ E->getInit(Index) : FillerExpr;
if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
Info, Subobject, Init) ||
!HandleLValueArrayAdjustment(Info, Init, Subobject,
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -2718,7 +2718,8 @@
Out << "il";
const InitListExpr *InitList = cast<InitListExpr>(E);
for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
- mangleExpression(InitList->getInit(i));
+ if (InitList->getInit(i))
+ mangleExpression(InitList->getInit(i));
Out << "E";
break;
}
@@ -2798,7 +2799,8 @@
// Only take InitListExprs apart for list-initialization.
const InitListExpr *InitList = cast<InitListExpr>(Init);
for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
- mangleExpression(InitList->getInit(i));
+ if (InitList->getInit(i))
+ mangleExpression(InitList->getInit(i));
} else
mangleExpression(Init);
}
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -433,6 +433,7 @@
}
llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
+ Expr *Filler = E->getArrayFiller();
// The 'current element to initialize'. The invariants on this
// variable are complicated. Essentially, after each iteration of
@@ -454,17 +455,19 @@
}
LValue elementLV = CGF.MakeAddrLValue(element, elementType);
- EmitInitializationToLValue(E->getInit(i), elementLV);
+ if (E->getInit(i))
+ EmitInitializationToLValue(E->getInit(i), elementLV);
+ else if (Filler)
+ EmitInitializationToLValue(Filler, elementLV);
}
// Check whether there's a non-trivial array-fill expression.
- Expr *filler = E->getArrayFiller();
- bool hasTrivialFiller = isTrivialFiller(filler);
+ bool hasTrivialFiller = isTrivialFiller(Filler);
// Any remaining elements need to be zero-initialized, possibly
// using the filler expression. We can skip this if the we're
// emitting to zeroed memory.
- if (NumInitElements != NumArrayElements &&
+ if (NumInitElements != NumArrayElements && Filler &&
!(Dest.isZeroed() && hasTrivialFiller &&
CGF.getTypes().isZeroInitializable(elementType))) {
@@ -493,10 +496,7 @@
// Emit the actual filler expression.
LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType);
- if (filler)
- EmitInitializationToLValue(filler, elementLV);
- else
- EmitNullInitializationToLValue(elementLV);
+ EmitInitializationToLValue(Filler, elementLV);
// Move on to the next element.
llvm::Value *nextElement =
@@ -1119,6 +1119,8 @@
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
Dest.getAlignment());
+ if (E->getPrevInitExpr())
+ EmitInitializationToLValue(E->getPrevInitExpr(), DestLV);
// Handle initialization of an array.
if (E->getType()->isArrayType()) {
@@ -1217,14 +1219,12 @@
LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, field);
// We never generate write-barries for initialized fields.
LV.setNonGC(true);
-
- if (curInitIndex < NumInitElements) {
+
+ if (curInitIndex < NumInitElements && E->getInit(curInitIndex)) {
// Store the initializer into the field.
EmitInitializationToLValue(E->getInit(curInitIndex++), LV);
- } else {
- // We're out of initalizers; default-initialize to null
- EmitNullInitializationToLValue(LV);
- }
+ } else
+ ++curInitIndex;
// Push a destructor if necessary.
// FIXME: if we have an array of structures, all explicitly
@@ -1306,7 +1306,7 @@
if (Field->getType()->isReferenceType())
NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits(
CGF.getTarget().getPointerWidth(0));
- else
+ else if (E)
NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF);
}
@@ -1317,7 +1317,8 @@
CharUnits NumNonZeroBytes = CharUnits::Zero();
for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
- NumNonZeroBytes += GetNumNonZeroBytesInInit(ILE->getInit(i), CGF);
+ if (ILE->getInit(i))
+ NumNonZeroBytes += GetNumNonZeroBytesInInit(ILE->getInit(i), CGF);
return NumNonZeroBytes;
}
Index: lib/CodeGen/CGExprCXX.cpp
===================================================================
--- lib/CodeGen/CGExprCXX.cpp
+++ lib/CodeGen/CGExprCXX.cpp
@@ -943,10 +943,24 @@
assert(getContext().hasSameUnqualifiedType(ElementType, Init->getType()) &&
"got wrong type of element to initialize");
- // If we have an empty initializer list, we can usually use memset.
- if (auto *ILE = dyn_cast<InitListExpr>(Init))
- if (ILE->getNumInits() == 0 && TryMemsetInitialization())
- return;
+ // If we have a struct whose every field is value-initialized, we can
+ // usually use memset.
+ if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
+ if (RType->getDecl()->isStruct()) {
+ unsigned NumFields = 0;
+ for (auto *Field : RType->getDecl()->fields())
+ if (!Field->isUnnamedBitfield())
+ ++NumFields;
+ if (ILE->getNumInits() == NumFields)
+ for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
+ if (!isa<ImplicitValueInitExpr>(ILE->getInit(i)))
+ --NumFields;
+ if (ILE->getNumInits() == NumFields && TryMemsetInitialization())
+ return;
+ }
+ }
+ }
// Create the loop blocks.
llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -746,6 +746,14 @@
unsigned NumInitElements = ILE->getNumInits();
unsigned NumElements = AType->getNumElements();
+ // Get filler value for implicitly initialized 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);
+
// Initialising an array requires us to automatically
// initialise any elements that have not been initialised explicitly
unsigned NumInitableElts = std::min(NumInitElements, NumElements);
@@ -752,12 +760,14 @@
// Copy initializer elements.
std::vector<llvm::Constant*> Elts;
- Elts.reserve(NumInitableElts + NumElements);
+ Elts.reserve(NumElements);
bool RewriteType = false;
- for (unsigned i = 0; i < NumInitableElts; ++i) {
- Expr *Init = ILE->getInit(i);
- llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+ for (unsigned i = 0; i < NumElements; ++i) {
+ Expr *Init = i < NumInitElements ? ILE->getInit(i) : nullptr;
+ llvm::Constant *C = FillC;
+ if (Init)
+ C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
if (!C)
return nullptr;
RewriteType |= (C->getType() != ElemTy);
@@ -764,17 +774,9 @@
Elts.push_back(C);
}
- // 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)
+ if (!FillC)
return nullptr;
- RewriteType |= (fillC->getType() != ElemTy);
- Elts.resize(NumElements, fillC);
+ RewriteType |= (FillC->getType() != ElemTy);
if (RewriteType) {
// FIXME: Try to avoid packing the array
@@ -799,6 +801,8 @@
}
llvm::Constant *VisitInitListExpr(InitListExpr *ILE) {
+ assert(!ILE->getPrevInitExpr() && "unexpected non-const initializer");
+
if (ILE->getType()->isArrayType())
return EmitArrayInitialization(ILE);
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -8276,7 +8276,8 @@
isInitList = true;
InitFieldIndex.push_back(0);
for (auto Child : InitList->children()) {
- CheckExpr(cast<Expr>(Child));
+ if (Child)
+ CheckExpr(cast<Expr>(Child));
++InitFieldIndex.back();
}
InitFieldIndex.pop_back();
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -306,7 +306,8 @@
QualType CurrentObjectType,
InitListExpr *StructuredList,
unsigned StructuredIndex,
- SourceRange InitRange);
+ SourceRange InitRange,
+ bool IsFullyOverwritten = false);
void UpdateStructuredListElement(InitListExpr *StructuredList,
unsigned &StructuredIndex,
Expr *expr);
@@ -460,6 +461,25 @@
unsigned NumInits = ILE->getNumInits();
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
+
+ // Assume we have the following definitions:
+ //
+ // struct P { char x[6][6]; };
+ // struct P xp = { .x[1] = "bar" };
+ // struct PP { struct P lp; };
+ // struct PP l = { .lp = xp, .lp.x[1][2] = 'f' };
+ //
+ // l.lp.x[1][0..1] should not be filled with implicit initializers because the
+ // previous initializers will provide values for them; l.lp.x[1] will be "baf".
+ //
+ // But if we have:
+ // struct PP l = { .lp = xp, .lp.x[1] = { [2] = 'f' } };
+ //
+ // l.lp.x[1][0..1] are implicitly initialized and do not use values from the
+ // previous initializer; l.lp.x[1] will be "\0\0f\0\0\0".
+ if (ILE->getPrevInitExpr())
+ return;
+
if (Init >= NumInits || !ILE->getInit(Init)) {
// C++1y [dcl.init.aggr]p7:
// If there are fewer initializer-clauses in the list than there are
@@ -529,6 +549,24 @@
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
+ // Assume we have the following definitions:
+ //
+ // struct P { char x[6][6]; };
+ // struct P xp = { .x[1] = "bar" };
+ // struct PP { struct P lp; };
+ // struct PP l = { .lp = xp, .lp.x[1][2] = 'f' };
+ //
+ // l.lp.x[1][0..1] should not be filled with implicit initializers because the
+ // previous initializers will provide values for them; l.lp.x[1] will be "baf".
+ //
+ // But if we have:
+ // struct PP l = { .lp = xp, .lp.x[1] = { [2] = 'f' } };
+ //
+ // l.lp.x[1][0..1] are implicitly initialized and do not use values from the
+ // previous initializer; l.lp.x[1] will be "\0\0f\0\0\0".
+ if (ILE->getPrevInitExpr())
+ return;
+
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
const RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
@@ -543,6 +581,13 @@
}
}
} else {
+ unsigned NumFields = 0;
+ for (auto *Field : RDecl->fields())
+ if (!Field->isUnnamedBitfield())
+ ++NumFields;
+ if (ILE->getNumInits() < NumFields)
+ ILE->resizeInits(SemaRef.Context, NumFields);
+
unsigned Init = 0;
for (auto *Field : RDecl->fields()) {
if (Field->isUnnamedBitfield())
@@ -789,6 +834,10 @@
return;
}
+ SourceLocation LocStart = IList->getInit(Index) ?
+ IList->getInit(Index)->getLocStart() : IList->getLocStart();
+ SourceRange SrcRange = IList->getInit(Index) ?
+ IList->getInit(Index)->getSourceRange() : IList->getSourceRange();
if (StructuredIndex == 1 &&
IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
SIF_None) {
@@ -798,8 +847,7 @@
hadError = true;
}
// Special-case
- SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK)
- << IList->getInit(Index)->getSourceRange();
+ SemaRef.Diag(LocStart, DK) << SrcRange;
} else if (!T->isIncompleteType()) {
// Don't complain for incomplete types, since we'll get an error
// elsewhere
@@ -821,8 +869,7 @@
hadError = true;
}
- SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK)
- << initKind << IList->getInit(Index)->getSourceRange();
+ SemaRef.Diag(LocStart, DK) << initKind << SrcRange;
}
}
@@ -904,20 +951,36 @@
StructuredList, StructuredIndex);
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
- if (!ElemType->isRecordType() || ElemType->isAggregateType()) {
- InitListExpr *InnerStructuredList
- = getStructuredSubobjectInit(IList, Index, ElemType,
- StructuredList, StructuredIndex,
- SubInitList->getSourceRange());
- CheckExplicitInitList(Entity, SubInitList, ElemType,
- InnerStructuredList);
- ++StructuredIndex;
- ++Index;
- return;
+ if (SubInitList->getNumInits() == 1 &&
+ IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) ==
+ SIF_None) {
+ expr = SubInitList->getInit(0);
+ } else {
+ if (!ElemType->isRecordType() || ElemType->isAggregateType()) {
+ InitListExpr *InnerStructuredList
+ = getStructuredSubobjectInit(IList, Index, ElemType,
+ StructuredList, StructuredIndex,
+ SubInitList->getSourceRange(), true);
+ CheckExplicitInitList(Entity, SubInitList, ElemType,
+ InnerStructuredList);
+
+ if (!hadError && !VerifyOnly) {
+ bool RequiresSecondPass = false;
+ FillInEmptyInitializations(Entity, InnerStructuredList,
+ RequiresSecondPass);
+ if (RequiresSecondPass && !hadError)
+ FillInEmptyInitializations(Entity, InnerStructuredList,
+ RequiresSecondPass);
+ }
+
+ ++StructuredIndex;
+ ++Index;
+ return;
+ }
+ assert(SemaRef.getLangOpts().CPlusPlus &&
+ "non-aggregate records are only possible in C++");
+ // C++ initialization is handled later.
}
- assert(SemaRef.getLangOpts().CPlusPlus &&
- "non-aggregate records are only possible in C++");
- // C++ initialization is handled later.
} else if (isa<ImplicitValueInitExpr>(expr)) {
// This happens during template instantiation when we see an InitListExpr
// that we've already checked once.
@@ -1363,7 +1426,7 @@
const ArrayType *arrayType = SemaRef.Context.getAsArrayType(DeclType);
// Check for the special-case of initializing an array with a string.
- if (Index < IList->getNumInits()) {
+ if (Index < IList->getNumInits() && IList->getInit(Index)) {
if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) ==
SIF_None) {
// We place the string literal directly into the resulting
@@ -1409,6 +1472,10 @@
QualType elementType = arrayType->getElementType();
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
+ if (!Init) {
+ ++Index;
+ continue;
+ }
if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
// If we're not the subobject that matches up with the '{' for
// the designator, we shouldn't be handling the
@@ -2303,7 +2370,8 @@
QualType CurrentObjectType,
InitListExpr *StructuredList,
unsigned StructuredIndex,
- SourceRange InitRange) {
+ SourceRange InitRange,
+ bool IsFullyOverwritten) {
if (VerifyOnly)
return nullptr; // No structured list in verification-only mode.
Expr *ExistingInit = nullptr;
@@ -2313,29 +2381,9 @@
ExistingInit = StructuredList->getInit(StructuredIndex);
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
- return Result;
+ if (!IsFullyOverwritten)
+ return Result;
- if (ExistingInit) {
- // We are creating an initializer list that initializes the
- // subobjects of the current object, but there was already an
- // initialization that completely initialized the current
- // subobject, e.g., by a compound literal:
- //
- // struct X { int a, b; };
- // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
- //
- // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
- // designated initializer re-initializes the whole
- // subobject [0], overwriting previous initializers.
- SemaRef.Diag(InitRange.getBegin(),
- diag::warn_subobject_initializer_overrides)
- << InitRange;
- SemaRef.Diag(ExistingInit->getLocStart(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0
- << ExistingInit->getSourceRange();
- }
-
InitListExpr *Result
= new (SemaRef.Context) InitListExpr(SemaRef.Context,
InitRange.getBegin(), None,
@@ -2383,13 +2431,68 @@
// Link this new initializer list into the structured initializer
// lists.
- if (StructuredList)
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
+ bool ExistingInitIsDecomposed = false;
+ if (StructuredList) {
+ // There might have already been initializers for subobjects of the current
+ // object, but a subsequent initializer list will overwrite the entirety
+ // of the current object. (See DR 253 and C99 6.7.8p21). e.g.,
+ //
+ // struct P { char x[6]; };
+ // struct P l = { .x[2] = 'x', .x = { [0] = 'f' } };
+ //
+ // The first designated initializer is ignored, and l.x is just "f".
+ Result->setPrevInitExpr(StructuredList->updateInit(SemaRef.Context,
+ StructuredIndex, Result));
+ if (!Result->getPrevInitExpr() && StructuredList->hasArrayFiller())
+ Result->setPrevInitExpr(StructuredList->getArrayFiller());
+ if (IsFullyOverwritten)
+ Result->setPrevInitExpr(nullptr);
+ if (Expr *PrevInitExpr = Result->getPrevInitExpr())
+ if (PrevInitExpr->isConstantInitializer(SemaRef.Context, false)) {
+ Result->partialMergeFrom(SemaRef.Context, PrevInitExpr);
+ Result->setPrevInitExpr(nullptr);
+ ExistingInitIsDecomposed = true;
+ }
+ }
else {
Result->setSyntacticForm(IList);
SyntacticToSemantic[IList] = Result;
}
+ // If we decomposed an aggregate initializer into individual components, we
+ // do not issue diagnostics here; instead we wait till later and issue
+ // diagnostics on each individual component.
+ if (ExistingInit && !ExistingInitIsDecomposed) {
+ // We are creating an initializer list that initializes the
+ // subobjects of the current object, but there was already an
+ // initialization that completely initialized the current
+ // subobject, e.g., by a compound literal:
+ //
+ // struct X { int a, b; };
+ // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
+ //
+ // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
+ // designated initializer re-initializes the whole
+ // subobject [0], overwriting previous initializers.
+ SemaRef.Diag(InitRange.getBegin(),
+ diag::warn_subobject_initializer_overrides)
+ << InitRange;
+
+ // We need to check on source range validity because the previous
+ // initializer does not have to be an explicit initializer. e.g.,
+ //
+ // struct P { int a, b; };
+ // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ //
+ // There is an overwrite taking place because the first braced initializer
+ // list "{ .a = 2 }" already provides value for .p.b (which is zero).
+ if (ExistingInit->getSourceRange().isValid())
+ SemaRef.Diag(ExistingInit->getLocStart(),
+ diag::note_previous_initializer)
+ << /*FIXME:has side effects=*/0
+ << ExistingInit->getSourceRange();
+ }
+
return Result;
}
@@ -2408,11 +2511,28 @@
SemaRef.Diag(expr->getLocStart(),
diag::warn_initializer_overrides)
<< expr->getSourceRange();
- SemaRef.Diag(PrevInit->getLocStart(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0
- << PrevInit->getSourceRange();
+
+ // We need to check on source range validity because the previous
+ // initializer does not have to be an explicit initializer.
+ // struct P { int a, b; };
+ // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ // There is an overwrite taking place because the first braced initializer
+ // list "{ .a = 2 }' already provides value for .p.b (which is zero).
+ if (PrevInit->getSourceRange().isValid())
+ SemaRef.Diag(PrevInit->getLocStart(),
+ diag::note_previous_initializer)
+ << /*FIXME:has side effects=*/0
+ << PrevInit->getSourceRange();
}
+ // It is also possible to overwrite an implicitly initialized array element:
+ // struct S { char L[6]; } var[] = {
+ // { { 'f', 'o', 'o' } }, // var[0].L[3..6] zero-initialized, and then
+ // [0].L[4] = 'x' }; // var[0].L[4] was overriden
+ else if (StructuredList->hasArrayFiller()) {
+ SemaRef.Diag(expr->getLocStart(),
+ diag::warn_initializer_overrides)
+ << expr->getSourceRange();
+ }
++StructuredIndex;
}
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -4470,6 +4470,8 @@
if (!X.isNull()) {
for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) {
Expr *Init = From->getInit(i);
+ if (!Init)
+ continue;
ImplicitConversionSequence ICS =
TryCopyInitialization(S, Init, X, SuppressUserConversions,
InOverloadResolution,
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -2996,6 +2996,9 @@
SmallVectorImpl<Expr *> &Outputs,
bool *ArgChanged) {
for (unsigned I = 0; I != NumInputs; ++I) {
+ if (!Inputs[I])
+ continue;
+
// If requested, drop call arguments that need to be dropped.
if (IsCall && getDerived().DropCallArgument(Inputs[I])) {
if (ArgChanged)
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -716,8 +716,11 @@
E->setSyntacticForm(SyntForm);
E->setLBraceLoc(ReadSourceLocation(Record, Idx));
E->setRBraceLoc(ReadSourceLocation(Record, Idx));
+ bool isPrevInitExpr = Record[Idx++];
bool isArrayFiller = Record[Idx++];
Expr *filler = nullptr;
+ if (isPrevInitExpr)
+ E->PrevInitExpr = Reader.ReadSubExpr();
if (isArrayFiller) {
filler = Reader.ReadSubExpr();
E->ArrayFillerOrUnionFieldInit = filler;
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -679,8 +679,12 @@
Writer.AddStmt(E->getSyntacticForm());
Writer.AddSourceLocation(E->getLBraceLoc(), Record);
Writer.AddSourceLocation(E->getRBraceLoc(), Record);
- bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is<Expr*>();
+ bool isPrevInitExpr = !!E->getPrevInitExpr();
+ Record.push_back(isPrevInitExpr);
+ bool isArrayFiller = E->hasArrayFiller();
Record.push_back(isArrayFiller);
+ if (isPrevInitExpr)
+ Writer.AddStmt(E->getPrevInitExpr());
if (isArrayFiller)
Writer.AddStmt(E->getArrayFiller());
else
Index: test/CodeGen/Inputs/stdio.h
===================================================================
--- test/CodeGen/Inputs/stdio.h
+++ test/CodeGen/Inputs/stdio.h
@@ -1,4 +1,5 @@
struct FILE;
+extern int printf(const char *format, ...);
extern int vfprintf(struct FILE *s, const char *format, __builtin_va_list arg);
extern int vprintf(const char *format, __builtin_va_list arg);
Index: test/CodeGen/partial-reinitialization1.c
===================================================================
--- test/CodeGen/partial-reinitialization1.c
+++ test/CodeGen/partial-reinitialization1.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -isystem %S/Inputs %s -emit-llvm -o - | FileCheck %s
+
+struct P1 {
+ struct Q1 {
+ char a[6];
+ char b[6];
+ } q;
+};
+
+// CHECK: { [6 x i8] c"foo\00\00\00", [6 x i8] c"\00x\00\00\00\00" }
+struct P1 l1 = {
+ (struct Q1){ "foo", "bar" },
+ .q.b = { "boo" },
+ .q.b = { [1] = 'x' }
+};
+
+// CHECK: { [6 x i8] c"foo\00\00\00", [6 x i8] c"bxo\00\00\00" }
+struct P1 l1a = {
+ (struct Q1){ "foo", "bar" },
+ .q.b = { "boo" },
+ .q.b[1] = 'x'
+};
+
+
+struct P2 { char x[6]; };
+
+// CHECK: { [6 x i8] c"n\00\00\00\00\00" }
+struct P2 l2 = {
+ .x = { [1] = 'o' },
+ .x = { [0] = 'n' }
+};
+
+struct P3 {
+ struct Q3 {
+ struct R1 {
+ int a, b, c;
+ } r1;
+
+ struct R2 {
+ int d, e, f;
+ } r2;
+ } q;
+};
+
+// CHECK: @l3 = global %struct.P3 { %struct.Q3 { %struct.R1 { i32 1, i32 2, i32 3 }, %struct.R2 { i32 0, i32 10, i32 0 } } }
+struct P3 l3 = {
+ (struct Q3){ { 1, 2, 3 }, { 4, 5, 6 } },
+ .q.r2 = { 7, 8, 9 },
+ .q.r2 = { .e = 10 }
+};
+
+// This bit is taken from Sema/wchar.c so we can avoid the wchar.h include.
+typedef __WCHAR_TYPE__ wchar_t;
+#if defined(_WIN32) || defined(_M_IX86) || defined(__CYGWIN__) \
+ || defined(_M_X64) || defined(SHORT_WCHAR)
+ #define WCHAR_T_TYPE unsigned short
+#elif defined(__sun) || defined(__AuroraUX__)
+ #define WCHAR_T_TYPE long
+#else /* Solaris or AuroraUX. */
+ #define WCHAR_T_TYPE int
+#endif
+
+struct P4 {
+ wchar_t x[6];
+};
+
+// CHECK: { [6 x i32] [i32 102, i32 111, i32 120, i32 0, i32 0, i32 0] }
+struct P4 l4 = { { L"foo" }, .x[2] = L'x' };
Index: test/CodeGen/partial-reinitialization2.c
===================================================================
--- test/CodeGen/partial-reinitialization2.c
+++ test/CodeGen/partial-reinitialization2.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -isystem %S/Inputs %s -emit-llvm -o - | lli | FileCheck %s
+
+#include <stdio.h>
+
+struct P1 { char x[6]; } g1 = { "foo" };
+struct LP1 { struct P1 p1; };
+
+struct P2 { int a, b, c; } g2 = { 1, 2, 3 };
+struct LP2 { struct P2 p2; };
+
+
+void test1(void)
+{ // CHECK: fox
+ struct LP1 l = { .p1 = g1, .p1.x[2] = 'x' };
+ int i;
+ for (i = 0; i < 6; i ++)
+ printf("%c", l.p1.x[i]);
+ printf("\n");
+}
+
+void test2(void)
+{ // CHECK: fro
+ struct LP1 l = { .p1 = g1, .p1.x[1] = 'r' };
+ int i;
+ for (i = 0; i < 6; i ++)
+ printf("%c", l.p1.x[i]);
+ printf("\n");
+}
+
+void test3(void)
+{ // CHECK: 1 10 3
+ struct LP2 l = { .p2 = g2, .p2.b = 10 };
+ printf("%d %d %d\n", l.p2.a, l.p2.b, l.p2.c);
+}
+
+int main()
+{
+ test1();
+ test2();
+ test3();
+ return 0;
+}
Index: test/PCH/designated-init.c.h
===================================================================
--- test/PCH/designated-init.c.h
+++ test/PCH/designated-init.c.h
@@ -40,3 +40,16 @@
},
}
};
+
+struct P1 {
+ struct Q1 {
+ char a[6];
+ char b[6];
+ } q;
+};
+
+struct P1 l1 = {
+ (struct Q1){ "foo", "bar" },
+ .q.b = { "boo" },
+ .q.b = { [1] = 'x' }
+};
Index: test/Sema/designated-initializers.c
===================================================================
--- test/Sema/designated-initializers.c
+++ test/Sema/designated-initializers.c
@@ -45,8 +45,8 @@
struct point array2[10] = {
[10].x = 2.0, // expected-error{{array designator index (10) exceeds array bounds (10)}}
- [4 ... 5].y = 2.0,
- [4 ... 6] = { .x = 3, .y = 4.0 }
+ [4 ... 5].y = 2.0, // expected-note 2 {{previous initialization is here}}
+ [4 ... 6] = { .x = 3, .y = 4.0 } // expected-warning 2 {{subobject initialization overrides initialization of other fields within its enclosing subobject}}
};
struct point array3[10] = {
@@ -130,10 +130,10 @@
void test() {
struct X xs[] = {
[0] = (struct X){1, 2}, // expected-note{{previous initialization is here}}
- [0].c = 3, // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+ [0].c = 3, // expected-warning{{initializer overrides prior initialization of this subobject}}
(struct X) {4, 5, 6}, // expected-note{{previous initialization is here}}
- [1].b = get8(), // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
- [0].b = 8
+ [1].b = get8(), // expected-warning{{initializer overrides prior initialization of this subobject}}
+ [0].b = 8 // expected-warning{{initializer overrides prior initialization of this subobject}}
};
}
@@ -318,7 +318,7 @@
.a = 1 // expected-note{{previous initialization is here}}
} },
.a = 2, // expected-warning{{initializer overrides prior initialization of this subobject}}
- .b = 3
+ .b = 3 // expected-warning{{initializer overrides prior initialization of this subobject}}
};
struct ds ds1 = { .c = 0 };
struct ds ds2 = { { {
@@ -339,5 +339,15 @@
int M;
} overwrite_string2[] = {
{ { "foo" }, 1 },
- [0].L[4] = 'x' // no-warning
+ [0].L[4] = 'x' // expected-warning{{initializer overrides prior initialization of this subobject}}
};
+struct overwrite_string_struct
+overwrite_string3[] = {
+ "foo", 1,
+ [0].L[4] = 'x' // expected-warning{{initializer overrides prior initialization of this subobject}}
+};
+struct overwrite_string_struct
+overwrite_string4[] = {
+ { { 'f', 'o', 'o' }, 1 },
+ [0].L[4] = 'x' // expected-warning{{initializer overrides prior initialization of this subobject}}
+};
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits