Updating the patch to trunk r232975.
A very gentle ping?
http://reviews.llvm.org/D5789
Files:
include/clang/AST/DataRecursiveASTVisitor.h
include/clang/AST/Expr.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/StmtNodes.td
include/clang/Serialization/ASTBitCodes.h
lib/AST/Expr.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprCXX.cpp
lib/Sema/SemaExceptionSpec.cpp
lib/Sema/SemaInit.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/designated-initializer.c
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
tools/libclang/CXCursor.cpp
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/AST/DataRecursiveASTVisitor.h
===================================================================
--- include/clang/AST/DataRecursiveASTVisitor.h
+++ include/clang/AST/DataRecursiveASTVisitor.h
@@ -2204,9 +2204,11 @@
DEF_TRAVERSE_STMT(CXXThrowExpr, {})
DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
+DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {})
DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
DEF_TRAVERSE_STMT(GNUNullExpr, {})
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
+DEF_TRAVERSE_STMT(NoInitExpr, {})
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -4262,6 +4262,86 @@
}
};
+/// \brief Represents a place-holder for an object not to be initialized by
+/// anything.
+///
+/// This only makes sense when it appears as part of an updater of a
+/// DesignatedInitUpdateExpr (see below). The base expression of a DIUE
+/// initializes a big object, and the NoInitExpr's mark the spots within the
+/// big object not to be overwritten by the updater.
+///
+/// \see DesignatedInitUpdateExpr
+class NoInitExpr : public Expr {
+public:
+ explicit NoInitExpr(QualType ty)
+ : Expr(NoInitExprClass, ty, VK_RValue, OK_Ordinary,
+ false, false, ty->isInstantiationDependentType(), false) { }
+
+ explicit NoInitExpr(EmptyShell Empty)
+ : Expr(NoInitExprClass, Empty) { }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == NoInitExprClass;
+ }
+
+ SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
+
+ // Iterators
+ child_range children() { return child_range(); }
+};
+
+// In cases like:
+// struct Q { int a, b, c; };
+// Q *getQ();
+// void foo() {
+// struct A { Q q; } a = { *getQ(), .q.b = 3 };
+// }
+//
+// We will have an InitListExpr for a, with type A, and then a
+// DesignatedInitUpdateExpr for "a.q" with type Q. The "base" for this DIUE
+// is the call expression *getQ(); the "updater" for the DIUE is ".q.b = 3"
+//
+class DesignatedInitUpdateExpr : public Expr {
+ // BaseAndUpdaterExprs[0] is the base expression;
+ // BaseAndUpdaterExprs[1] is an InitListExpr overwriting part of the base.
+ Stmt *BaseAndUpdaterExprs[2];
+ SourceLocation LBraceLoc, RBraceLoc;
+
+public:
+ DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lbraceloc,
+ Expr* baseExprs, SourceLocation rbraceloc);
+
+ explicit DesignatedInitUpdateExpr(EmptyShell Empty)
+ : Expr(DesignatedInitUpdateExprClass, Empty) { }
+
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DesignatedInitUpdateExprClass;
+ }
+
+ SourceLocation getLBraceLoc() const { return LBraceLoc; }
+ void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
+ SourceLocation getRBraceLoc() const { return RBraceLoc; }
+ void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; }
+
+ Expr *getBase() const { return cast<Expr>(BaseAndUpdaterExprs[0]); }
+ void setBase(Expr *Base) { BaseAndUpdaterExprs[0] = Base; }
+
+ InitListExpr *getUpdater() const {
+ return cast<InitListExpr>(BaseAndUpdaterExprs[1]);
+ }
+ void setUpdater(Expr *Updater) { BaseAndUpdaterExprs[1] = Updater; }
+
+ // Iterators
+ // children = the base and the updater
+ child_range children() {
+ return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2);
+ }
+};
+
/// \brief Represents an implicitly-generated value initialization of
/// an object of a given type.
///
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2234,9 +2234,11 @@
DEF_TRAVERSE_STMT(CXXThrowExpr, {})
DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
+DEF_TRAVERSE_STMT(DesignatedInitUpdateExpr, {})
DEF_TRAVERSE_STMT(ExtVectorElementExpr, {})
DEF_TRAVERSE_STMT(GNUNullExpr, {})
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, {})
+DEF_TRAVERSE_STMT(NoInitExpr, {})
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, {})
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -77,7 +77,9 @@
def ExtVectorElementExpr : DStmt<Expr>;
def InitListExpr : DStmt<Expr>;
def DesignatedInitExpr : DStmt<Expr>;
+def DesignatedInitUpdateExpr : DStmt<Expr>;
def ImplicitValueInitExpr : DStmt<Expr>;
+def NoInitExpr : DStmt<Expr>;
def ParenListExpr : DStmt<Expr>;
def VAArgExpr : DStmt<Expr>;
def GenericSelectionExpr : DStmt<Expr>;
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1196,8 +1196,12 @@
EXPR_INIT_LIST,
/// \brief A DesignatedInitExpr record.
EXPR_DESIGNATED_INIT,
+ /// \brief A DesignatedInitUpdateExpr record.
+ EXPR_DESIGNATED_INIT_UPDATE,
/// \brief An ImplicitValueInitExpr record.
EXPR_IMPLICIT_VALUE_INIT,
+ /// \brief An NoInitExpr record.
+ EXPR_NO_INIT,
/// \brief A VAArgExpr record.
EXPR_VA_ARG,
/// \brief An AddrLabelExpr record.
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -2772,6 +2772,13 @@
const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
return Exp->isConstantInitializer(Ctx, false, Culprit);
}
+ case DesignatedInitUpdateExprClass: {
+ const DesignatedInitUpdateExpr *DIUE = cast<DesignatedInitUpdateExpr>(this);
+ if (!DIUE->getBase()->isConstantInitializer(Ctx, false, Culprit))
+ return false;
+ assert(false && "DIUE->getBase() should not be a constant expression");
+ break;
+ }
case InitListExprClass: {
const InitListExpr *ILE = cast<InitListExpr>(this);
if (ILE->getType()->isArrayType()) {
@@ -2818,6 +2825,7 @@
break;
}
case ImplicitValueInitExprClass:
+ case NoInitExprClass:
return true;
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()
@@ -2925,6 +2933,7 @@
case UnaryExprOrTypeTraitExprClass:
case AddrLabelExprClass:
case GNUNullExprClass:
+ case NoInitExprClass:
case CXXBoolLiteralExprClass:
case CXXNullPtrLiteralExprClass:
case CXXThisExprClass:
@@ -2975,6 +2984,7 @@
case CompoundLiteralExprClass:
case ExtVectorElementExprClass:
case DesignatedInitExprClass:
+ case DesignatedInitUpdateExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
case CXXStdInitializerListExprClass:
@@ -3981,6 +3991,30 @@
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
+DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C,
+ SourceLocation lbraceloc, Expr *baseExpr, SourceLocation rbraceloc)
+ : Expr(DesignatedInitUpdateExprClass, baseExpr->getType(), VK_RValue,
+ OK_Ordinary, false, false, false, false),
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc) {
+ BaseAndUpdaterExprs[0] = baseExpr;
+
+ InitListExpr *ILE = new (C) InitListExpr(C, lbraceloc, None, rbraceloc);
+ ILE->setType(baseExpr->getType());
+ BaseAndUpdaterExprs[1] = ILE;
+}
+
+SourceLocation DesignatedInitUpdateExpr::getLocStart() const {
+ if (LBraceLoc.isValid())
+ return LBraceLoc;
+ return getBase()->getLocStart();
+}
+
+SourceLocation DesignatedInitUpdateExpr::getLocEnd() const {
+ if (RBraceLoc.isValid())
+ return RBraceLoc;
+ return getUpdater()->getLocEnd();
+}
+
ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
ArrayRef<Expr*> exprs,
SourceLocation rparenloc)
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -183,6 +183,8 @@
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::AtomicExprClass:
case Expr::CXXFoldExprClass:
+ case Expr::NoInitExprClass:
+ case Expr::DesignatedInitUpdateExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -8671,6 +8671,8 @@
case Expr::CompoundLiteralExprClass:
case Expr::ExtVectorElementExprClass:
case Expr::DesignatedInitExprClass:
+ case Expr::NoInitExprClass:
+ case Expr::DesignatedInitUpdateExprClass:
case Expr::ImplicitValueInitExprClass:
case Expr::ParenListExprClass:
case Expr::VAArgExprClass:
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -2673,7 +2673,9 @@
// These all can only appear in local or variable-initialization
// contexts and so should never appear in a mangling.
case Expr::AddrLabelExprClass:
+ case Expr::DesignatedInitUpdateExprClass:
case Expr::ImplicitValueInitExprClass:
+ case Expr::NoInitExprClass:
case Expr::ParenListExprClass:
case Expr::LambdaExprClass:
case Expr::MSPropertyRefExprClass:
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1422,6 +1422,22 @@
PrintExpr(Node->getInit());
}
+void StmtPrinter::VisitDesignatedInitUpdateExpr(
+ DesignatedInitUpdateExpr *Node) {
+ OS << "{";
+ OS << "/*base*/";
+ PrintExpr(Node->getBase());
+ OS << ", ";
+
+ OS << "/*updater*/";
+ PrintExpr(Node->getUpdater());
+ OS << "}";
+}
+
+void StmtPrinter::VisitNoInitExpr(NoInitExpr *Node) {
+ OS << "/*no init*/";
+}
+
void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
if (Policy.LangOpts.CPlusPlus) {
OS << "/*implicit*/";
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -713,6 +713,16 @@
}
}
+// FIXME: how to test these functions?
+void StmtProfiler::VisitDesignatedInitUpdateExpr(
+ const DesignatedInitUpdateExpr *S) {
+ llvm_unreachable("Not implemented");
+}
+
+void StmtProfiler::VisitNoInitExpr(const NoInitExpr *S) {
+ llvm_unreachable("Not implemented");
+}
+
void StmtProfiler::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *S) {
VisitExpr(S);
}
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -159,10 +159,12 @@
EmitAggLoadOfLValue(E);
}
+ void VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E);
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
void VisitChooseExpr(const ChooseExpr *CE);
void VisitInitListExpr(InitListExpr *E);
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
+ void VisitNoInitExpr(NoInitExpr *E) { } // Do nothing.
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
Visit(DAE->getExpr());
}
@@ -1050,6 +1052,9 @@
return;
} else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
return EmitNullInitializationToLValue(LV);
+ } else if (isa<NoInitExpr>(E)) {
+ // Do nothing.
+ return;
} else if (type->isReferenceType()) {
RValue RV = CGF.EmitReferenceBindingToExpr(E);
return CGF.EmitStoreThroughLValue(RV, LV);
@@ -1270,6 +1275,15 @@
cleanupDominator->eraseFromParent();
}
+void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
+ AggValueSlot Dest = EnsureSlot(E->getType());
+
+ LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
+ Dest.getAlignment());
+ EmitInitializationToLValue(E->getBase(), DestLV);
+ VisitInitListExpr(E->getUpdater());
+}
+
//===----------------------------------------------------------------------===//
// Entry Points into this File
//===----------------------------------------------------------------------===//
Index: lib/CodeGen/CGExprCXX.cpp
===================================================================
--- lib/CodeGen/CGExprCXX.cpp
+++ lib/CodeGen/CGExprCXX.cpp
@@ -952,6 +952,25 @@
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();
llvm::BasicBlock *LoopBB = createBasicBlock("new.loop");
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1041,6 +1041,7 @@
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
+ case Expr::DesignatedInitUpdateExprClass:
case Expr::ExprWithCleanupsClass:
case Expr::ExtVectorElementExprClass:
case Expr::InitListExprClass:
@@ -1135,6 +1136,7 @@
case Expr::ImaginaryLiteralClass:
case Expr::ImplicitValueInitExprClass:
case Expr::IntegerLiteralClass:
+ case Expr::NoInitExprClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCBoolLiteralExprClass:
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);
@@ -317,11 +318,33 @@
SourceLocation Loc,
const InitializedEntity &Entity,
bool VerifyOnly);
+
+ // Explanation on the "FillWithNoInit" mode:
+ //
+ // Assume we have the following definitions (Case#1):
+ // struct P { char x[6][6]; } xp = { .x[1] = "bar" };
+ // struct PP { struct P lp; } l = { .lp = xp, .lp.x[1][2] = 'f' };
+ //
+ // l.lp.x[1][0..1] should not be filled with implicit initializers because the
+ // "base" initializer "xp" will provide values for them; l.lp.x[1] will be "baf".
+ //
+ // But if we have (Case#2):
+ // 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
+ // "base" initializer; l.lp.x[1] will be "\0\0f\0\0\0".
+ //
+ // To distinguish Case#1 from Case#2, and also to avoid leaving many "holes"
+ // in the InitListExpr, the "holes" in Case#1 are filled not with empty
+ // initializers but with a special "NoInitExpr" place holders, which tells the
+ // CodeGen not to generate any initializers for these parts.
void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
- InitListExpr *ILE, bool &RequiresSecondPass);
+ InitListExpr *ILE, bool &RequiresSecondPass,
+ bool FillWithNoInit = false);
void FillInEmptyInitializations(const InitializedEntity &Entity,
- InitListExpr *ILE, bool &RequiresSecondPass);
+ InitListExpr *ILE, bool &RequiresSecondPass,
+ bool FillWithNoInit = false);
bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
Expr *InitExpr, FieldDecl *Field,
bool TopLevelObject);
@@ -455,12 +478,26 @@
void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE,
- bool &RequiresSecondPass) {
+ bool &RequiresSecondPass,
+ bool FillWithNoInit) {
SourceLocation Loc = ILE->getLocEnd();
unsigned NumInits = ILE->getNumInits();
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
+
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
+ if (!RType->getDecl()->isUnion())
+ assert(Init < NumInits && "This ILE should have been expanded");
+
if (Init >= NumInits || !ILE->getInit(Init)) {
+ if (FillWithNoInit) {
+ Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType());
+ if (Init < NumInits)
+ ILE->setInit(Init, Filler);
+ else
+ ILE->updateInit(SemaRef.Context, Init, Filler);
+ return;
+ }
// C++1y [dcl.init.aggr]p7:
// If there are fewer initializer-clauses in the list than there are
// members in the aggregate, then each member not explicitly initialized
@@ -516,7 +553,11 @@
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
FillInEmptyInitializations(MemberEntity, InnerILE,
- RequiresSecondPass);
+ RequiresSecondPass, FillWithNoInit);
+ else if (DesignatedInitUpdateExpr *InnerDIUE
+ = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init)))
+ FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(),
+ RequiresSecondPass, /*FillWithNoInit =*/ true);
}
/// Recursively replaces NULL values within the given initializer list
@@ -525,7 +566,8 @@
void
InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE,
- bool &RequiresSecondPass) {
+ bool &RequiresSecondPass,
+ bool FillWithNoInit) {
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
@@ -533,16 +575,27 @@
const RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(),
- Entity, ILE, RequiresSecondPass);
+ Entity, ILE, RequiresSecondPass, FillWithNoInit);
else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) &&
cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) {
for (auto *Field : RDecl->fields()) {
if (Field->hasInClassInitializer()) {
- FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass);
+ FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass,
+ FillWithNoInit);
break;
}
}
} else {
+ // The fields beyond ILE->getNumInits() are default initialized, so in
+ // order to leave them uninitialized, the ILE is expanded and the extra
+ // fields are then filled with NoInitExpr.
+ 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())
@@ -551,7 +604,8 @@
if (hadError)
return;
- FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass);
+ FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass,
+ FillWithNoInit);
if (hadError)
return;
@@ -594,7 +648,9 @@
ElementEntity.setElementIndex(Init);
Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
- if (!InitExpr && !ILE->hasArrayFiller()) {
+ if (!InitExpr && Init < NumInits && ILE->hasArrayFiller())
+ ILE->setInit(Init, ILE->getArrayFiller());
+ else if (!InitExpr && !ILE->hasArrayFiller()) {
ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(),
ElementEntity,
/*VerifyOnly*/false);
@@ -603,6 +659,10 @@
return;
}
+ Expr *Filler = FillWithNoInit ?
+ new (SemaRef.Context) NoInitExpr(ElementType) :
+ ElementInit.getAs<Expr>();
+
if (hadError) {
// Do nothing
} else if (Init < NumInits) {
@@ -609,29 +669,34 @@
// For arrays, just set the expression used for value-initialization
// of the "holes" in the array.
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement)
- ILE->setArrayFiller(ElementInit.getAs<Expr>());
+ ILE->setArrayFiller(Filler);
else
- ILE->setInit(Init, ElementInit.getAs<Expr>());
+ ILE->setInit(Init, Filler);
} 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.getAs<Expr>());
+ ILE->setArrayFiller(Filler);
return;
}
- if (!isa<ImplicitValueInitExpr>(ElementInit.get())) {
+ if (!isa<ImplicitValueInitExpr>(Filler) && !isa<NoInitExpr>(Filler)) {
// Empty 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.getAs<Expr>());
+ ILE->updateInit(SemaRef.Context, Init, Filler);
RequiresSecondPass = true;
}
}
} else if (InitListExpr *InnerILE
= dyn_cast_or_null<InitListExpr>(InitExpr))
- FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass);
+ FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass,
+ FillWithNoInit);
+ else if (DesignatedInitUpdateExpr *InnerDIUE
+ = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr))
+ FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(),
+ RequiresSecondPass, /*FillWithNoInit =*/ true);
}
}
@@ -966,13 +1031,26 @@
StructuredList, StructuredIndex);
if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
- if (!SemaRef.getLangOpts().CPlusPlus) {
+ if (SubInitList->getNumInits() == 1 &&
+ IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) ==
+ SIF_None) {
+ expr = SubInitList->getInit(0);
+ } else if (!SemaRef.getLangOpts().CPlusPlus) {
InitListExpr *InnerStructuredList
= getStructuredSubobjectInit(IList, Index, ElemType,
StructuredList, StructuredIndex,
- SubInitList->getSourceRange());
+ 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;
@@ -1835,6 +1913,183 @@
}
+static void partialMergeFrom(const ASTContext &C, InitListExpr *TargetExpr,
+ Expr *BackgroundExpr) {
+ assert(!TargetExpr->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(TargetExpr->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 > TargetExpr->getNumInits())
+ TargetExpr->resizeInits(C, StrLen);
+
+ for (unsigned i = 0; i != StrLen; ++i) {
+ if (TargetExpr->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);
+ TargetExpr->setInit(i, ElementExpr);
+ }
+
+ if (ArraySize.ugt(StrLen))
+ TargetExpr->setArrayFiller(new (C) ImplicitValueInitExpr(CharTy));
+
+ return;
+ }
+
+ if (isa<ImplicitValueInitExpr>(BackgroundExpr)) {
+ unsigned NumInits = TargetExpr->getNumInits();
+
+ if (const RecordType *RType = TargetExpr->getType()->getAs<RecordType>()) {
+ const RecordDecl *RD = RType->getDecl();
+ unsigned i = 0;
+
+ unsigned NumFields = 0;
+ for (FieldDecl *FD : RD->fields()) {
+ if (FD->isUnnamedBitfield())
+ continue;
+ ++NumFields;
+ }
+ if (NumInits < NumFields)
+ TargetExpr->resizeInits(C, NumFields);
+
+ for (RecordDecl::field_iterator I = RD->field_begin(),E = RD->field_end();
+ I != E; ++I, ++i) {
+ FieldDecl *FD = *I;
+ if (FD->isUnnamedBitfield()) {
+ --i;
+ continue;
+ }
+
+ ImplicitValueInitExpr *EmptyInit =
+ new (C) ImplicitValueInitExpr(FD->getType());
+
+ if (!TargetExpr->getInit(i)) {
+ TargetExpr->setInit(i, EmptyInit);
+ continue;
+ }
+
+ // If this is not an aggregate type, we are done. The current
+ // initializer takes effect; the background initializer is overwritten.
+ Expr *ChildExpr = TargetExpr->getInit(i);
+ if (!ChildExpr->getType()->isAggregateType())
+ continue;
+
+ assert(isa<InitListExpr>(ChildExpr) && "expecting an init list expr");
+
+ InitListExpr *ChildILE = cast<InitListExpr>(ChildExpr);
+ partialMergeFrom(C, ChildILE, EmptyInit);
+
+ // Only look at the first initialization of a union
+ if (TargetExpr->getType()->isUnionType())
+ break;
+ }
+
+ return;
+ }
+
+ QualType ElementType;
+ bool IsArray = false;
+
+ if (const VectorType *VT = TargetExpr->getType()->getAs<VectorType>())
+ ElementType = VT->getElementType();
+ else if (const ArrayType *AT = C.getAsArrayType(TargetExpr->getType())) {
+ ElementType = AT->getElementType();
+ IsArray = true;
+ } else
+ ElementType = TargetExpr->getType();
+
+ ImplicitValueInitExpr *EmptyInit =
+ new (C) ImplicitValueInitExpr(ElementType);
+
+ if (IsArray)
+ TargetExpr->setArrayFiller(EmptyInit);
+
+ for (unsigned i = 0; i != NumInits; ++i) {
+ if (!TargetExpr->getInit(i) && !IsArray)
+ TargetExpr->setInit(i, EmptyInit);
+
+ // If this is not an aggregate type, we are done. The current
+ // initializer takes effect; the background initializer is overwritten.
+ Expr *ChildExpr = TargetExpr->getInit(i);
+ if (!ChildExpr->getType()->isAggregateType())
+ continue;
+
+ assert(isa<InitListExpr>(ChildExpr) && "expecting an init list expr");
+
+ InitListExpr *ChildILE = cast<InitListExpr>(ChildExpr);
+ partialMergeFrom(C, ChildILE, EmptyInit);
+ }
+
+ return;
+ }
+
+ assert(isa<InitListExpr>(BackgroundExpr) &&
+ "cannot break down background initializer!");
+ InitListExpr *BackgroundILE = cast<InitListExpr>(BackgroundExpr);
+ if (BackgroundILE->getNumInits() > TargetExpr->getNumInits())
+ TargetExpr->resizeInits(C, BackgroundILE->getNumInits());
+
+ for (unsigned i = 0; i != TargetExpr->getNumInits(); ++i) {
+ if (i >= BackgroundILE->getNumInits() || !BackgroundILE->getInit(i))
+ // Nothing to merge from.
+ continue;
+
+ if (!TargetExpr->getInit(i)) {
+ TargetExpr->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 = TargetExpr->getInit(i);
+ if (!ChildExpr->getType()->isAggregateType())
+ continue;
+
+ assert(isa<InitListExpr>(ChildExpr) && "expecting an init list expr");
+
+ InitListExpr *ChildILE = cast<InitListExpr>(ChildExpr);
+ partialMergeFrom(C, ChildILE, BackgroundILE->getInit(i));
+
+ // Only look at the first initialization of a union
+ if (TargetExpr->getType()->isUnionType())
+ break;
+ }
+
+ if (BackgroundILE->hasArrayFiller())
+ TargetExpr->setArrayFiller(BackgroundILE->getArrayFiller());
+}
+
/// @brief Check the well-formedness of a C99 designated initializer.
///
/// Determines whether the designated initializer @p DIE, which
@@ -1913,11 +2168,82 @@
// Determine the structural initializer list that corresponds to the
// current subobject.
- StructuredList = IsFirstDesignator? SyntacticToSemantic.lookup(IList)
- : getStructuredSubobjectInit(IList, Index, CurrentObjectType,
- StructuredList, StructuredIndex,
- SourceRange(D->getLocStart(),
- DIE->getLocEnd()));
+ if (IsFirstDesignator)
+ StructuredList = SyntacticToSemantic.lookup(IList);
+ else {
+ Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ?
+ StructuredList->getInit(StructuredIndex) : nullptr;
+ if (!ExistingInit && StructuredList->hasArrayFiller())
+ ExistingInit = StructuredList->getArrayFiller();
+
+ if (!ExistingInit)
+ StructuredList =
+ getStructuredSubobjectInit(IList, Index, CurrentObjectType,
+ StructuredList, StructuredIndex,
+ SourceRange(D->getLocStart(),
+ DIE->getLocEnd()));
+ else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
+ StructuredList = Result;
+ else if (ExistingInit->isConstantInitializer(SemaRef.Context, false)) {
+ InitListExpr *Result = new (SemaRef.Context) InitListExpr(
+ SemaRef.Context, D->getLocStart(), None, DIE->getLocEnd());
+
+ QualType ResultType = CurrentObjectType;
+ if (!ResultType->isArrayType())
+ ResultType = ResultType.getNonLValueExprType(SemaRef.Context);
+ Result->setType(ResultType);
+
+ // 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.
+ partialMergeFrom(SemaRef.Context, Result, ExistingInit);
+ ExistingInit = nullptr;
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
+ StructuredList = Result;
+ }
+ else {
+ if (DesignatedInitUpdateExpr *E =
+ dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
+ StructuredList = E->getUpdater();
+ else {
+ DesignatedInitUpdateExpr *DIUE =
+ new (SemaRef.Context) DesignatedInitUpdateExpr(SemaRef.Context,
+ D->getLocStart(), ExistingInit,
+ DIE->getLocEnd());
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
+ StructuredList = DIUE->getUpdater();
+ }
+
+ // 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(D->getLocStart(),
+ diag::warn_subobject_initializer_overrides)
+ << SourceRange(D->getLocStart(), DIE->getLocEnd());
+
+ // 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();
+ }
+ }
assert(StructuredList && "Expected a structured initializer list");
}
@@ -2367,7 +2693,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;
@@ -2377,7 +2704,16 @@
ExistingInit = StructuredList->getInit(StructuredIndex);
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
- return Result;
+ // 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".
+ if (!IsFullyOverwritten)
+ return Result;
if (ExistingInit) {
// We are creating an initializer list that initializes the
@@ -2472,11 +2808,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/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -7923,8 +7923,26 @@
E->usesGNUSyntax(), Init.get());
}
+// Seems that if TransformInitListExpr() only works on the syntactic form of an
+// InitListExpr, then a DesignatedInitUpdateExpr is not encountered.
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformDesignatedInitUpdateExpr(
+ DesignatedInitUpdateExpr *E) {
+ llvm_unreachable("not implemented");
+ return ExprError();
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformNoInitExpr(
+ NoInitExpr *E) {
+ llvm_unreachable("not implemented");
+ return ExprError();
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformImplicitValueInitExpr(
ImplicitValueInitExpr *E) {
TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -801,6 +801,18 @@
Designators.data(), Designators.size());
}
+void ASTStmtReader::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
+ VisitExpr(E);
+ E->setLBraceLoc(ReadSourceLocation(Record, Idx));
+ E->setRBraceLoc(ReadSourceLocation(Record, Idx));
+ E->setBase(Reader.ReadSubExpr());
+ E->setUpdater(Reader.ReadSubExpr());
+}
+
+void ASTStmtReader::VisitNoInitExpr(NoInitExpr *E) {
+ VisitExpr(E);
+}
+
void ASTStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
VisitExpr(E);
}
@@ -2506,10 +2518,18 @@
break;
+ case EXPR_DESIGNATED_INIT_UPDATE:
+ S = new (Context) DesignatedInitUpdateExpr(Empty);
+ break;
+
case EXPR_IMPLICIT_VALUE_INIT:
S = new (Context) ImplicitValueInitExpr(Empty);
break;
+ case EXPR_NO_INIT:
+ S = new (Context) NoInitExpr(Empty);
+ break;
+
case EXPR_VA_ARG:
S = new (Context) VAArgExpr(Empty);
break;
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -774,7 +774,9 @@
RECORD(EXPR_EXT_VECTOR_ELEMENT);
RECORD(EXPR_INIT_LIST);
RECORD(EXPR_DESIGNATED_INIT);
+ RECORD(EXPR_DESIGNATED_INIT_UPDATE);
RECORD(EXPR_IMPLICIT_VALUE_INIT);
+ RECORD(EXPR_NO_INIT);
RECORD(EXPR_VA_ARG);
RECORD(EXPR_ADDR_LABEL);
RECORD(EXPR_STMT);
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -737,6 +737,20 @@
Code = serialization::EXPR_DESIGNATED_INIT;
}
+void ASTStmtWriter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLBraceLoc(), Record);
+ Writer.AddSourceLocation(E->getRBraceLoc(), Record);
+ Writer.AddStmt(E->getBase());
+ Writer.AddStmt(E->getUpdater());
+ Code = serialization::EXPR_DESIGNATED_INIT_UPDATE;
+}
+
+void ASTStmtWriter::VisitNoInitExpr(NoInitExpr *E) {
+ VisitExpr(E);
+ Code = serialization::EXPR_NO_INIT;
+}
+
void ASTStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
VisitExpr(E);
Code = serialization::EXPR_IMPLICIT_VALUE_INIT;
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -859,6 +859,7 @@
// Cases not handled yet; but will handle some day.
case Stmt::DesignatedInitExprClass:
+ case Stmt::DesignatedInitUpdateExprClass:
case Stmt::ExtVectorElementExprClass:
case Stmt::ImaginaryLiteralClass:
case Stmt::ObjCAtCatchStmtClass:
@@ -891,6 +892,7 @@
case Stmt::CXXBoolLiteralExprClass:
case Stmt::ObjCBoolLiteralExprClass:
case Stmt::FloatingLiteralClass:
+ case Stmt::NoInitExprClass:
case Stmt::SizeOfPackExprClass:
case Stmt::StringLiteralClass:
case Stmt::ObjCStringLiteralClass:
Index: test/Analysis/designated-initializer.c
===================================================================
--- test/Analysis/designated-initializer.c
+++ test/Analysis/designated-initializer.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 \
+// RUN: | FileCheck %s
+
+struct Q { int a, b, c; };
+union UQ { struct Q q; };
+union UQ getUQ() {
+ union UQ u = { { 1, 2, 3 } };
+ return u;
+}
+
+void test() {
+ struct LUQ { union UQ uq; } var = { getUQ(), .uq.q.a = 100 };
+ struct Q s[] = {
+ [0] = (struct Q){1, 2},
+ [0].c = 3
+ };
+}
+
+// CHECK: void test()
+// CHECK: [B1]
+// CHECK: 1: getUQ
+// CHECK: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, union UQ (*)())
+// CHECK: 3: [B1.2]()
+// CHECK: 4: 100
+// CHECK: 5: /*no init*/
+// CHECK: 6: /*no init*/
+// CHECK: 7: {[B1.4], [B1.5], [B1.6]}
+// CHECK: 8: {[B1.7]}
+// CHECK: 9: {/*base*/[B1.3], /*updater*/[B1.8]}
+// CHECK: 10: {[B1.3], .uq.q.a = [B1.4]}
+// CHECK: 11: struct LUQ var = {getUQ(), .uq.q.a = 100};
+// CHECK: 12: 1
+// CHECK: 13: 2
+// CHECK: 14: 3
+// CHECK: 15: {[B1.12], [B1.13], [B1.14]}
+// CHECK: 16: {[0] = (struct Q){[B1.12], [B1.13]}, [0].c = [B1.14]}
+// CHECK: 17: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3};
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,74 @@
+// 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;
+
+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' };
+
+struct P5 {
+ int x;
+ struct Q5 {
+ int a, b, c;
+ } q;
+ int y;
+};
+
+// A three-pass test
+// CHECK: @l5 = global %struct.P5 { i32 1, %struct.Q5 { i32 6, i32 9, i32 8 }, i32 5 }
+struct P5 l5 = { 1, { 2, 3, 4 }, 5,
+ .q = { 6, 7, 8 },
+ .q.b = 9 };
Index: test/CodeGen/partial-reinitialization2.c
===================================================================
--- test/CodeGen/partial-reinitialization2.c
+++ test/CodeGen/partial-reinitialization2.c
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -isystem %S/Inputs %s -emit-llvm -o - \
+// RUN: | lli -force-interpreter | 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; };
+struct LP2P2 { struct P2 p1, p2; };
+union UP2 { struct P2 p2; };
+
+struct LP3 { struct P1 p1[2]; } g3 = { { "dog" }, { "cat" } };
+struct LLP3 { struct LP3 l3; };
+union ULP3 { struct LP3 l3; };
+
+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);
+}
+
+#if 0
+// FIXME: with -force-interpreter, the use of struct type here ran into bv21177
+// without -force-interpreter, MCJIT on Windows does not quite work yet.
+struct P2 get235()
+{
+ struct P2 p = { 2, 3, 5 };
+ return p;
+}
+
+struct LP2P2 get456789()
+{
+ struct LP2P2 l = { { 4, 5, 6 }, { 7, 8, 9 } };
+ return l;
+}
+
+union UP2 get123()
+{
+ union UP2 u = { { 1, 2, 3 } };
+ return u;
+}
+#else
+struct P2 my235 = { 2, 3, 5 };
+struct LP2P2 my456789 = { { 4, 5, 6 }, { 7, 8, 9 } };
+union UP2 my123 = { { 1, 2, 3 } };
+#define get235() my235
+#define get456789() my456789
+#define get123() my123
+#endif
+
+void test4(void)
+{ // CHECK: 100 2 3
+ struct LUP2 { union UP2 up; } var = { get123(), .up.p2.a = 100 };
+ printf("%d %d %d\n", var.up.p2.a, var.up.p2.b, var.up.p2.c);
+}
+
+void test5(void)
+{ // CHECK: 0 78 0 0 0 0
+ struct LLP3 var = { .l3 = g3, .l3.p1 = { [0] = g1 }, .l3.p1[1].x[1] = 'x' };
+ int i;
+ for (i = 0; i < 6; i ++)
+ printf("%x ", var.l3.p1[1].x[i]);
+ printf("\n");
+}
+
+void test6(void)
+{ // CHECK: 2 10 5 : 7 8 9
+ struct LLP2P2 { struct LP2P2 lp; } var = { get456789(),
+ .lp.p1 = get235(),
+ .lp.p1.b = 10 };
+ printf("%d %d %d : %d %d %d\n",
+ var.lp.p1.a, var.lp.p1.b, var.lp.p1.c,
+ var.lp.p2.a, var.lp.p2.b, var.lp.p2.c);
+}
+
+int main()
+{
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+ test6();
+ return 0;
+}
Index: test/PCH/designated-init.c.h
===================================================================
--- test/PCH/designated-init.c.h
+++ test/PCH/designated-init.c.h
@@ -40,3 +40,25 @@
},
}
};
+
+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' }
+};
+
+extern struct Q1 *foo();
+static struct P1 test_foo() {
+ struct P1 l = { *foo(),
+ .q.b = { "boo" },
+ .q.b = { [1] = 'x' }
+ };
+ return l;
+}
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}}
+};
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -235,11 +235,13 @@
case Stmt::CXXUuidofExprClass:
case Stmt::ChooseExprClass:
case Stmt::DesignatedInitExprClass:
+ case Stmt::DesignatedInitUpdateExprClass:
case Stmt::ExprWithCleanupsClass:
case Stmt::ExpressionTraitExprClass:
case Stmt::ExtVectorElementExprClass:
case Stmt::ImplicitCastExprClass:
case Stmt::ImplicitValueInitExprClass:
+ case Stmt::NoInitExprClass:
case Stmt::MaterializeTemporaryExprClass:
case Stmt::ObjCIndirectCopyRestoreExprClass:
case Stmt::OffsetOfExprClass:
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits