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

Reply via email to