Ping.
Re-based patch to trunk r222712.

http://reviews.llvm.org/D5789

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

Reply via email to