Code generation support for C99 designated initializers.

The approach I've taken in this patch is relatively straightforward,
although the code itself is non-trivial. Essentially, as we process
an initializer list we build up a fully-explicit representation of the
initializer list, where each of the subobject initializations occurs
in order. Designators serve to "fill in" subobject initializations in
a non-linear way. The fully-explicit representation makes initializer
lists (both with and without designators) easy to grok for codegen and
later semantic analyses. We keep the syntactic form of the initializer
list linked into the AST for those clients interested in exactly what
the user wrote.

Known limitations:
  - Designating a member of a union that isn't the first member may
    result in bogus initialization (we warn about this)
  - GNU array-range designators are not supported (we warn about this)



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63242 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 8e43f99..ed73bfa 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -221,13 +221,31 @@
 
 InitListExpr::InitListExpr(SourceLocation lbraceloc, 
                            Expr **initExprs, unsigned numInits,
-                           SourceLocation rbraceloc, bool hadDesignators)
+                           SourceLocation rbraceloc)
   : Expr(InitListExprClass, QualType()),
-    LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), HadDesignators(hadDesignators) {
+    LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) {
 
   InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
 }
 
+void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) {
+  for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx)
+    delete InitExprs[Idx];
+  InitExprs.resize(NumInits, 0);
+}
+
+Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
+  if (Init >= InitExprs.size()) {
+    InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0);
+    InitExprs.back() = expr;
+    return 0;
+  }
+  
+  Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
+  InitExprs[Init] = expr;
+  return Result;
+}
+
 /// getFunctionType - Return the underlying function type for this block.
 ///
 const FunctionType *BlockExpr::getFunctionType() const {
@@ -740,6 +758,12 @@
   return isEvaluatable(Ctx);
 }
 
+bool Expr::hasSideEffects(ASTContext &Ctx) const {
+  EvalResult Result;
+  Evaluate(Result, Ctx);
+  return Result.HasSideEffects;
+}
+
 /// isIntegerConstantExpr - this recursive routine will test if an expression is
 /// an integer constant expression. Note: With the introduction of VLA's in
 /// C99 the result of the sizeof operator is no longer always a constant
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 80de5b8..7a558ab 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -872,13 +872,38 @@
   OS << "{ ";
   for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
     if (i) OS << ", ";
-    PrintExpr(Node->getInit(i));
+    if (Node->getInit(i))
+      PrintExpr(Node->getInit(i));
+    else
+      OS << "0";
   }
   OS << " }";
 }
 
 void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
-  // FIXME!
+  for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(),
+                      DEnd = Node->designators_end();
+       D != DEnd; ++D) {
+    if (D->isFieldDesignator()) {
+      if (D->getDotLoc().isInvalid())
+        OS << D->getFieldName()->getName() << ":";
+      else
+        OS << "." << D->getFieldName()->getName();
+    } else {
+      OS << "[";
+      if (D->isArrayDesignator()) {
+        PrintExpr(Node->getArrayIndex(*D));
+      } else {
+        PrintExpr(Node->getArrayRangeStart(*D));
+        OS << " ... ";
+        PrintExpr(Node->getArrayRangeEnd(*D));        
+      }
+      OS << "]";
+    }
+  }
+
+  OS << " = ";
+  PrintExpr(Node->getInit());
 }
 
 void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
@@ -1187,7 +1212,9 @@
 //===----------------------------------------------------------------------===//
 
 void Stmt::dumpPretty() const {
-  printPretty(llvm::errs());
+  llvm::raw_ostream &OS = llvm::errs();
+  printPretty(OS);
+  OS.flush();
 }
 
 void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper) const {
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 9181bf6..2534a14 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -71,7 +71,7 @@
   void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
     EmitAggLoadOfLValue(E);
   }
-
+  
   // Operators.
   //  case Expr::UnaryOperatorClass:
   //  case Expr::CastExprClass: 
@@ -303,11 +303,6 @@
 }
 
 void AggExprEmitter::EmitNonConstInit(InitListExpr *E) {
-  if (E->hadDesignators()) {
-    CGF.ErrorUnsupported(E, "initializer list with designators");
-    return;
-  }
-  
   const llvm::PointerType *APType =
     cast<llvm::PointerType>(DestPtr->getType());
   const llvm::Type *DestType = APType->getElementType();
@@ -346,6 +341,8 @@
   // FIXME: Are initializers affected by volatile?
   if (E->getType()->isComplexType()) {
     CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
+  } else if (isa<CXXZeroInitValueExpr>(E)) {
+    EmitNullInitializationToLValue(LV, E->getType());
   } else if (CGF.hasAggregateLLVMType(E->getType())) {
     CGF.EmitAnyExpr(E, LV.getAddress(), false);
   } else {
@@ -380,11 +377,6 @@
 }
 
 void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
-  if (E->hadDesignators()) {
-    CGF.ErrorUnsupported(E, "initializer list with designators");
-    return;
-  }
-
 #if 0
   // FIXME: Disabled while we figure out what to do about 
   // test/CodeGen/bitfield.c
@@ -426,7 +418,7 @@
 
     uint64_t NumArrayElements = AType->getNumElements();
     QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
-    ElementType =CGF.getContext().getAsArrayType(ElementType)->getElementType();
+    ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
     
     unsigned CVRqualifier = ElementType.getCVRQualifiers();
 
@@ -479,7 +471,7 @@
     }
 
     // Unions only initialize one field.
-    // (things can get weird with designators, but they aren't
+    // (FIXME: things can get weird with designators, but they aren't
     // supported yet.)
     if (isUnion)
       break;
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 32d126e..3b6ebb4 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -242,6 +242,8 @@
     const llvm::Type *Ty = ConvertType(ILE->getType());
 
     // Find the field decl we're initializing, if any
+    // FIXME: C99 designated initializers won't always initialize the 
+    // first field
     int FieldNo = 0; // Field no in RecordDecl
     FieldDecl* curField = 0;
     for (RecordDecl::field_iterator Field = RD->field_begin(),
@@ -304,12 +306,6 @@
       return llvm::Constant::getNullValue(RetTy);
     }
     
-    // FIXME: We don't codegen or sema designators yet.
-    if (ILE->hadDesignators()) {
-      CGM.ErrorUnsupported(ILE, "initializer list with designators");
-      return llvm::UndefValue::get(ConvertType(ILE->getType()));
-    }
-
     if (ILE->getType()->isArrayType())
       return EmitArrayInitialization(ILE);
 
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 33c5a61..dd8b300 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -176,11 +176,6 @@
     if (!VType) 
       return Visit(E->getInit(0));
     
-    if (E->hadDesignators()) {
-      CGF.ErrorUnsupported(E, "initializer list with designators");
-      return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
-    }
-    
     unsigned NumVectorElements = VType->getNumElements();
     const llvm::Type *ElementType = VType->getElementType();
 
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index d017e6f..8cf10ff 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -28,6 +28,7 @@
 #include "llvm/ADT/OwningPtr.h"
 #include <string>
 #include <vector>
+#include <map>
 
 namespace llvm {
   class APSInt;
@@ -1835,38 +1836,67 @@
 class InitListChecker {
   Sema *SemaRef;
   bool hadError;
+  std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
+  InitListExpr *FullyStructuredList;
   
   void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, 
-                             unsigned &Index);
+                             unsigned &Index, InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckExplicitInitList(InitListExpr *IList, QualType &T,
-                             unsigned &Index);
-
+                             unsigned &Index, InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, 
                              bool SubobjectIsDesignatorContext, 
-                             unsigned &Index);
+                             unsigned &Index,
+                             InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckSubElementType(InitListExpr *IList, QualType ElemType, 
-                           Expr *expr, unsigned &Index);
+                           Expr *expr, unsigned &Index,
+                           InitListExpr *StructuredInitList,
+                           unsigned &StructuredInitIndex);
   // FIXME: Does DeclType need to be a reference type?
   void CheckScalarType(InitListExpr *IList, QualType &DeclType, 
-                       Expr *expr, unsigned &Index);
-  void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index);
+                       Expr *expr, unsigned &Index,
+                       InitListExpr *StructuredInitList,
+                       unsigned &StructuredInitIndex);
+  void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
+                       InitListExpr *StructuredInitList,
+                       unsigned &StructuredInitIndex);
   void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, 
                              RecordDecl::field_iterator Field, 
-                             bool SubobjectIsDesignatorContext, unsigned &Index);
+                             bool SubobjectIsDesignatorContext, unsigned &Index,
+                             InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckArrayType(InitListExpr *IList, QualType &DeclType, 
                       llvm::APSInt elementIndex, 
-                      bool SubobjectIsDesignatorContext, unsigned &Index);
+                      bool SubobjectIsDesignatorContext, unsigned &Index,
+                      InitListExpr *StructuredInitList,
+                      unsigned &StructuredInitIndex);
   bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, 
                                   DesignatedInitExpr::designators_iterator D,
                                   QualType &CurrentObjectType, 
                                   RecordDecl::field_iterator *NextField,
                                   llvm::APSInt *NextElementIndex,
-                                  unsigned &Index);
+                                  unsigned &Index,
+                                  InitListExpr *StructuredList,
+                                  unsigned &StructuredIndex);
+  InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+                                           QualType CurrentObjectType,
+                                           InitListExpr *StructuredList,
+                                           unsigned StructuredIndex,
+                                           SourceRange InitRange);
+  void UpdateStructuredListElement(InitListExpr *StructuredInitList,
+                                   unsigned &StructuredInitIndex,
+                                   Expr *expr);
   int numArrayElements(QualType DeclType);
   int numStructUnionElements(QualType DeclType);
 public:
   InitListChecker(Sema *S, InitListExpr *IL, QualType &T);
   bool HadError() { return hadError; }
+
+  // @brief Retrieves the fully-structured initializer list used for
+  // semantic analysis and code generation.
+  InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
 };
 
 /// BlockSemaInfo - When a block is being parsed, this contains information
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index cfbd288..79efc7d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1136,6 +1136,9 @@
   }
 
   InitListChecker CheckInitList(this, InitList, DeclType);
+  if (!CheckInitList.HadError())
+    Init = CheckInitList.getFullyStructuredList();
+
   return CheckInitList.HadError();
 }
 
@@ -2209,6 +2212,12 @@
     for (unsigned i = 0; i < numInits; i++) {
       // FIXME: Need to get the type of the declaration for C++,
       // because it could be a reference?
+
+      // Implicitly-generated value initializations are okay.
+      if (isa<CXXZeroInitValueExpr>(Exp->getInit(i)) &&
+          cast<CXXZeroInitValueExpr>(Exp->getInit(i))->isImplicit()) 
+        continue;
+
       if (CheckForConstantInitializer(Exp->getInit(i),
                                       Exp->getInit(i)->getType()))
         return true;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 770404d..064b851 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1985,7 +1985,7 @@
   // CheckInitializer() - it requires knowledge of the object being intialized. 
 
   InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit, 
-                                    RBraceLoc, Designators.hasAnyDesignators());
+                                               RBraceLoc);
   E->setType(Context.VoidTy); // FIXME: just a place holder for now.
   return Owned(E);
 }
@@ -3988,8 +3988,7 @@
   // Otherwise, create a compound literal expression as the base, and
   // iteratively process the offsetof designators.
   InitListExpr *IList =
-      new (Context) InitListExpr(SourceLocation(), 0, 0,
-                                 SourceLocation(), false);
+      new (Context) InitListExpr(SourceLocation(), 0, 0, SourceLocation());
   IList->setType(ArgTy);
   Expr *Res =
       new (Context) CompoundLiteralExpr(SourceLocation(), ArgTy, IList, false);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 041e994..511a394 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -15,19 +15,73 @@
 #include "clang/Parse/Designator.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/Basic/DiagnosticSema.h"
-#include <algorithm> // for std::count_if
-#include <functional> // for std::mem_fun
-
 using namespace clang;
 
+/// Recursively replaces NULL values within the given initializer list
+/// with expressions that perform value-initialization of the
+/// appropriate type.
+static void fillInValueInitializations(ASTContext &Context, InitListExpr *ILE) {
+  assert((ILE->getType() != Context.VoidTy) && "Should not have void type");
+  if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
+    unsigned Init = 0, NumInits = ILE->getNumInits();
+    for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(),
+                                 FieldEnd = RType->getDecl()->field_end();
+         Field != FieldEnd; ++Field) {
+      if (Field->isUnnamedBitfield())
+        continue;
+
+      if (Init >= NumInits)
+        break;
+
+      // FIXME: Check for fields with reference type in C++?
+      if (!ILE->getInit(Init))
+        ILE->setInit(Init, 
+                     new (Context) CXXZeroInitValueExpr(Field->getType(), 
+                                                        SourceLocation(),
+                                                        SourceLocation()));
+      else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+        fillInValueInitializations(Context, InnerILE);
+      ++Init;
+    }
+
+    return;
+  } 
+
+  QualType ElementType;
+  
+  if (const ArrayType *AType = Context.getAsArrayType(ILE->getType()))
+    ElementType = AType->getElementType();
+  else if (const VectorType *VType = ILE->getType()->getAsVectorType())
+    ElementType = VType->getElementType();
+  else 
+    ElementType = ILE->getType();
+  
+  for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits; 
+       ++Init) {
+    if (!ILE->getInit(Init))
+      ILE->setInit(Init, new (Context) CXXZeroInitValueExpr(ElementType, 
+                                                            SourceLocation(),
+                                                            SourceLocation()));
+    else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+      fillInValueInitializations(Context, InnerILE);
+  }
+}
+
 InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
   hadError = false;
   SemaRef = S;
 
   unsigned newIndex = 0;
+  unsigned newStructuredIndex = 0;
+  FullyStructuredList 
+    = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange());
+  CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex);
 
-  CheckExplicitInitList(IL, T, newIndex);
+  if (!hadError) {
+    fillInValueInitializations(SemaRef->Context, FullyStructuredList);
+  }
 }
 
 int InitListChecker::numArrayElements(QualType DeclType) {
@@ -42,17 +96,22 @@
 
 int InitListChecker::numStructUnionElements(QualType DeclType) {
   RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
-  const int InitializableMembers 
-    = std::count_if(structDecl->field_begin(), structDecl->field_end(),
-                    std::mem_fun(&FieldDecl::getDeclName));
+  int InitializableMembers = 0;
+  for (RecordDecl::field_iterator Field = structDecl->field_begin(),
+                               FieldEnd = structDecl->field_end();
+       Field != FieldEnd; ++Field) {
+    if ((*Field)->getIdentifier() || !(*Field)->isBitField())
+      ++InitializableMembers;
+  }
   if (structDecl->isUnion())
     return std::min(InitializableMembers, 1);
   return InitializableMembers - structDecl->hasFlexibleArrayMember();
 }
 
 void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, 
-                                            QualType T, unsigned &Index) {
-  llvm::SmallVector<Expr*, 4> InitExprs;
+                                            QualType T, unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   int maxElements = 0;
   
   if (T->isArrayType())
@@ -64,45 +123,39 @@
   else
     assert(0 && "CheckImplicitInitList(): Illegal type");
 
+  // FIXME: Perhaps we should move this warning elsewhere?
   if (maxElements == 0) {
     SemaRef->Diag(ParentIList->getInit(Index)->getLocStart(),
                   diag::err_implicit_empty_initializer);
+    ++Index;
     hadError = true;
     return;
   }
 
-  // Check the element types *before* we create the implicit init list;
-  // otherwise, we might end up taking the wrong number of elements
-  unsigned NewIndex = Index;
-  CheckListElementTypes(ParentIList, T, false, NewIndex);
+  // Build a structured initializer list corresponding to this subobject.
+  InitListExpr *StructuredSubobjectInitList
+    = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList, 
+                                 StructuredIndex, 
+                                 ParentIList->getInit(Index)->getSourceRange());
+  unsigned StructuredSubobjectInitIndex = 0;
 
-  for (int i = 0; i < maxElements; ++i) {
-    // Don't attempt to go past the end of the init list
-    if (Index >= ParentIList->getNumInits())
-      break;
-    Expr* expr = ParentIList->getInit(Index);
-    
-    // Add the expr to the new implicit init list and remove if from the old.
-    InitExprs.push_back(expr);
-    ParentIList->removeInit(Index);
-  }
-  // Synthesize an "implicit" InitListExpr (marked by the invalid source locs).
-  InitListExpr *ILE = new InitListExpr(SourceLocation(), 
-                                       &InitExprs[0], InitExprs.size(), 
-                                       SourceLocation(),
-                                       ParentIList->hadDesignators());
-  ILE->setType(T);
-
-  // Modify the parent InitListExpr to point to the implicit InitListExpr.
-  ParentIList->addInit(Index, ILE);
+  // Check the element types and build the structural subobject.
+  CheckListElementTypes(ParentIList, T, false, Index,
+                        StructuredSubobjectInitList, 
+                        StructuredSubobjectInitIndex);
 }
 
 void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
-                                            unsigned &Index) {
+                                            unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
-
-  CheckListElementTypes(IList, T, true, Index);
+  SyntacticToSemantic[IList] = StructuredList;
+  StructuredList->setSyntacticForm(IList);
+  CheckListElementTypes(IList, T, true, Index, StructuredList, 
+                        StructuredIndex);
   IList->setType(T);
+  StructuredList->setType(T);
   if (hadError)
     return;
 
@@ -131,27 +184,31 @@
 void InitListChecker::CheckListElementTypes(InitListExpr *IList,
                                             QualType &DeclType, 
                                             bool SubobjectIsDesignatorContext,
-                                            unsigned &Index) {
+                                            unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   if (DeclType->isScalarType()) {
-    CheckScalarType(IList, DeclType, 0, Index);
+    CheckScalarType(IList, DeclType, 0, Index, StructuredList, StructuredIndex);
   } else if (DeclType->isVectorType()) {
-    CheckVectorType(IList, DeclType, Index);
+    CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
   } else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
     if (DeclType->isStructureType() || DeclType->isUnionType()) {
       RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
       CheckStructUnionTypes(IList, DeclType, RD->field_begin(), 
-                            SubobjectIsDesignatorContext, Index);
+                            SubobjectIsDesignatorContext, Index,
+                            StructuredList, StructuredIndex);
     } else if (DeclType->isArrayType()) {
       llvm::APSInt Zero(
                       SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()),
                       false);
-      CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index);
+      CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
+                     StructuredList, StructuredIndex);
     }
     else
-      assert(0 && "Aggregate that isn't a function or array?!");
+      assert(0 && "Aggregate that isn't a structure or array?!");
   } else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
     // This type is invalid, issue a diagnostic.
-    Index++;
+    ++Index;
     SemaRef->Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
       << DeclType;
     hadError = true;
@@ -165,31 +222,46 @@
 void InitListChecker::CheckSubElementType(InitListExpr *IList,
                                           QualType ElemType, 
                                           Expr *expr,
-                                          unsigned &Index) {
+                                          unsigned &Index,
+                                          InitListExpr *StructuredList,
+                                          unsigned &StructuredIndex) {
   if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
     unsigned newIndex = 0;
-    CheckExplicitInitList(SubInitList, ElemType, newIndex);
-    Index++;
+    unsigned newStructuredIndex = 0;
+    InitListExpr *newStructuredList 
+      = getStructuredSubobjectInit(IList, Index, ElemType,
+                                   StructuredList, StructuredIndex,
+                                   SubInitList->getSourceRange());
+    CheckExplicitInitList(SubInitList, ElemType, newIndex, 
+                          newStructuredList, newStructuredIndex);
+    ++StructuredIndex;
+    ++Index;
   } else if (StringLiteral *lit =
              SemaRef->IsStringLiteralInit(expr, ElemType)) {
     SemaRef->CheckStringLiteralInit(lit, ElemType);
-    Index++;
+    UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
+    ++Index;
   } else if (ElemType->isScalarType()) {
-    CheckScalarType(IList, ElemType, expr, Index);
+    CheckScalarType(IList, ElemType, expr, Index, StructuredList, 
+                    StructuredIndex);
   } else if (expr->getType()->getAsRecordType() &&
              SemaRef->Context.typesAreCompatible(
                expr->getType().getUnqualifiedType(),
                ElemType.getUnqualifiedType())) {
-    Index++;
+    UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+    ++Index;
     // FIXME: Add checking
   } else {
-    CheckImplicitInitList(IList, ElemType, Index);
-    Index++;
-  }
+    CheckImplicitInitList(IList, ElemType, Index, StructuredList, 
+                          StructuredIndex);
+    ++StructuredIndex;
+ }
 }
 
 void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
-                                      Expr *expr, unsigned &Index) {
+                                      Expr *expr, unsigned &Index,
+                                      InitListExpr *StructuredList,
+                                      unsigned &StructuredIndex) {
   if (Index < IList->getNumInits()) {
     if (!expr)
       expr = IList->getInit(Index);
@@ -199,6 +271,7 @@
         << IList->getSourceRange();
       hadError = true;
       ++Index;
+      ++StructuredIndex;
       return;
     } else if (isa<DesignatedInitExpr>(expr)) {
       SemaRef->Diag(expr->getSourceRange().getBegin(), 
@@ -206,6 +279,7 @@
         << DeclType << expr->getSourceRange();
       hadError = true;
       ++Index;
+      ++StructuredIndex;
       return;
     }
 
@@ -219,18 +293,27 @@
         DIE->setInit(expr);
       else
         IList->setInit(Index, expr);
+
     }
+    if (hadError)
+      ++StructuredIndex;
+    else
+      UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
     ++Index;
   } else {
     SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
       << IList->getSourceRange();
     hadError = true;
+    ++Index;
+    ++StructuredIndex;
     return;
   }
 }
 
 void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, 
-                                      unsigned &Index) {
+                                      unsigned &Index,
+                                      InitListExpr *StructuredList,
+                                      unsigned &StructuredIndex) {
   if (Index < IList->getNumInits()) {
     const VectorType *VT = DeclType->getAsVectorType();
     int maxElements = VT->getNumElements();
@@ -240,7 +323,8 @@
       // Don't attempt to go past the end of the init list
       if (Index >= IList->getNumInits())
         break;
-      CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
+      CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
+                          StructuredList, StructuredIndex);
     }
   }
 }
@@ -248,12 +332,21 @@
 void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, 
                                      llvm::APSInt elementIndex,
                                      bool SubobjectIsDesignatorContext, 
-                                     unsigned &Index) {
+                                     unsigned &Index,
+                                     InitListExpr *StructuredList,
+                                     unsigned &StructuredIndex) {
   // Check for the special-case of initializing an array with a string.
   if (Index < IList->getNumInits()) {
     if (StringLiteral *lit = 
         SemaRef->IsStringLiteralInit(IList->getInit(Index), DeclType)) {
       SemaRef->CheckStringLiteralInit(lit, DeclType);
+      // We place the string literal directly into the resulting
+      // initializer list. This is the only place where the structure
+      // of the structured initializer list doesn't match exactly,
+      // because doing so would involve allocating one character
+      // constant for each string.
+      UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
+      StructuredList->resizeInits(SemaRef->Context, StructuredIndex);
       ++Index;
       return;
     }
@@ -267,11 +360,14 @@
                   diag::err_variable_object_no_init)
       << VAT->getSizeExpr()->getSourceRange();
     hadError = true;
+    ++Index;
+    ++StructuredIndex;
     return;
   }
 
   // We might know the maximum number of elements in advance.
-  llvm::APSInt maxElements(elementIndex.getBitWidth(), elementIndex.isUnsigned());
+  llvm::APSInt maxElements(elementIndex.getBitWidth(),
+                           elementIndex.isUnsigned());
   bool maxElementsKnown = false;
   if (const ConstantArrayType *CAT =
         SemaRef->Context.getAsConstantArrayType(DeclType)) {
@@ -295,7 +391,8 @@
       // Handle this designated initializer. elementIndex will be
       // updated to be the next array element we'll initialize.
       if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), 
-                                     DeclType, 0, &elementIndex, Index)) {
+                                     DeclType, 0, &elementIndex, Index,
+                                     StructuredList, StructuredIndex)) {
         hadError = true;
         continue;
       }
@@ -320,7 +417,8 @@
       break;
 
     // Check this element.
-    CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
+    CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
+                        StructuredList, StructuredIndex);
     ++elementIndex;
 
     // If the array is of incomplete type, keep track of the number of
@@ -348,7 +446,9 @@
                                             QualType DeclType, 
                                             RecordDecl::field_iterator Field,
                                             bool SubobjectIsDesignatorContext, 
-                                            unsigned &Index) {
+                                            unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
     
   // If the record is invalid, some of it's members are invalid. To avoid
@@ -376,7 +476,8 @@
       // Handle this designated initializer. Field will be updated to
       // the next field that we'll be initializing.
       if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), 
-                                     DeclType, &Field, 0, Index))
+                                     DeclType, &Field, 0, Index,
+                                     StructuredList, StructuredIndex))
         hadError = true;
 
       continue;
@@ -391,13 +492,14 @@
     if (Field->getType()->isIncompleteArrayType())
       break;
 
-    if (!Field->getIdentifier()) {
-      // Don't initialize unnamed fields, e.g. "int : 20;"
+    if (!Field->getIdentifier() && Field->isBitField()) {
+      // Don't initialize unnamed bitfields, e.g. "int : 20;"
       ++Field;
       continue;
     }
 
-    CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
+    CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index,
+                        StructuredList, StructuredIndex);
     if (DeclType->isUnionType()) // FIXME: designated initializers?
       break;
 
@@ -416,8 +518,7 @@
 /// IList, is well-formed for a current object of type @p DeclType
 /// (C99 6.7.8). The actual subobject that this designator refers to
 /// within the current subobject is returned in either 
-/// @p DesignatedField or @p DesignatedIndex (whichever is
-/// appropriate).
+/// @p NextField or @p NextElementIndex (whichever is appropriate).
 ///
 /// @param IList  The initializer list in which this designated
 /// initializer occurs.
@@ -439,6 +540,10 @@
 /// @param Index  Index into @p IList where the designated initializer
 /// @p DIE occurs.
 ///
+/// @param StructuredList  The initializer list expression that
+/// describes all of the subobject initializers in the order they'll
+/// actually be initialized.
+///
 /// @returns true if there was an error, false otherwise.
 bool 
 InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
@@ -447,16 +552,30 @@
                                       QualType &CurrentObjectType,
                                       RecordDecl::field_iterator *NextField,
                                       llvm::APSInt *NextElementIndex,
-                                      unsigned &Index) {
-  bool IsFirstDesignator = (D == DIE->designators_begin());
-
+                                      unsigned &Index,
+                                      InitListExpr *StructuredList,
+                                      unsigned &StructuredIndex) {
   if (D == DIE->designators_end()) {
     // Check the actual initialization for the designated object type.
     bool prevHadError = hadError;
-    CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index);
+    CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index,
+                        StructuredList, StructuredIndex);
     return hadError && !prevHadError;
   }
 
+  bool IsFirstDesignator = (D == DIE->designators_begin());
+  assert((IsFirstDesignator || StructuredList) && 
+         "Need a non-designated initializer list to start from");
+
+  // Determine the structural initializer list that corresponds to the
+  // current subobject.
+  StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
+    : getStructuredSubobjectInit(IList, Index, CurrentObjectType, StructuredList,
+                                 StructuredIndex,
+                                 SourceRange(D->getStartLocation(),
+                                             DIE->getSourceRange().getEnd()));
+  assert(StructuredList && "Expected a structured initializer list");
+
   if (D->isFieldDesignator()) {
     // C99 6.7.8p7:
     //
@@ -478,56 +597,95 @@
       return true;
     }
 
+    // Note: we perform a linear search of the fields here, despite
+    // the fact that we have a faster lookup method, because we always
+    // need to compute the field's index.
     IdentifierInfo *FieldName = D->getFieldName();
-    DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
-    FieldDecl *DesignatedField = 0;
-    if (Lookup.first == Lookup.second) {
-      // Lookup did not find anything with this name.
-      SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
-        << FieldName << CurrentObjectType;
-    } else if (isa<FieldDecl>(*Lookup.first)) {
-      // Name lookup found a field.
-      DesignatedField = cast<FieldDecl>(*Lookup.first);
-      // FIXME: Make sure this isn't a field in an anonymous
-      // struct/union.
-    } else {
-      // Name lookup found something, but it wasn't a field.
-      SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
-        << FieldName;
-      SemaRef->Diag((*Lookup.first)->getLocation(), 
-                    diag::note_field_designator_found);
+    unsigned FieldIndex = 0;
+    RecordDecl::field_iterator Field = RT->getDecl()->field_begin(),
+                            FieldEnd = RT->getDecl()->field_end();
+    for (; Field != FieldEnd; ++Field) {
+      if (Field->isUnnamedBitfield())
+        continue;
+
+      if (Field->getIdentifier() == FieldName)
+        break;
+
+      ++FieldIndex;
     }
 
-    if (!DesignatedField) {
+    if (Field == FieldEnd) {
+      // We did not find the field we're looking for. Produce a
+      // suitable diagnostic and return a failure.
+      DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+      if (Lookup.first == Lookup.second) {
+        // Name lookup didn't find anything.
+        SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+          << FieldName << CurrentObjectType;
+      } else {
+        // Name lookup found something, but it wasn't a field.
+        SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
+          << FieldName;
+        SemaRef->Diag((*Lookup.first)->getLocation(), 
+                      diag::note_field_designator_found);
+      }
+
+      ++Index;
+      return true;
+    } else if (cast<RecordDecl>((*Field)->getDeclContext())
+                 ->isAnonymousStructOrUnion()) {
+      SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_anon_class)
+        << FieldName
+        << (cast<RecordDecl>((*Field)->getDeclContext())->isUnion()? 2 : 
+            (int)SemaRef->getLangOptions().CPlusPlus);
+      SemaRef->Diag((*Field)->getLocation(), diag::note_field_designator_found);
       ++Index;
       return true;
     }
-        
+
+    // All of the fields of a union are located at the same place in
+    // the initializer list.
+    // FIXME: Need to tell CodeGen which type to initialize to. ImplicitCastExpr?
+    if (RT->getDecl()->isUnion() && FieldIndex != 0) {
+      SemaRef->Diag(D->getStartLocation(), 
+                    diag::warn_designator_into_union_broken_init)
+        << SourceRange(D->getStartLocation(), DIE->getSourceRange().getEnd());
+      FieldIndex = 0;
+    }
+
     // Update the designator with the field declaration.
-    D->setField(DesignatedField);
+    D->setField(*Field);
       
+    // Make sure that our non-designated initializer list has space
+    // for a subobject corresponding to this field.
+    if (FieldIndex >= StructuredList->getNumInits())
+      StructuredList->resizeInits(SemaRef->Context, FieldIndex + 1);
+
     // Recurse to check later designated subobjects.
-    QualType FieldType = DesignatedField->getType();
-    if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index))
+    QualType FieldType = (*Field)->getType();
+    unsigned newStructuredIndex = FieldIndex;
+    if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
+                                   StructuredList, newStructuredIndex))
       return true;
 
     // Find the position of the next field to be initialized in this
     // subobject.
-    RecordDecl::field_iterator Field(DeclContext::decl_iterator(DesignatedField),
-                                     RT->getDecl()->decls_end());
     ++Field;
+    ++FieldIndex;
 
     // If this the first designator, our caller will continue checking
     // the rest of this struct/class/union subobject.
     if (IsFirstDesignator) {
       if (NextField)
         *NextField = Field;
+      StructuredIndex = FieldIndex;
       return false;
     }
 
     // Check the remaining fields within this class/struct/union subobject.
     bool prevHadError = hadError;
-    CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index);
+    CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
+                          StructuredList, FieldIndex);
     return hadError && !prevHadError;
   }
 
@@ -561,6 +719,9 @@
   else {
     assert(D->isArrayRangeDesignator() && "Need array-range designator");
     IndexExpr = DIE->getArrayRangeEnd(*D);
+    SemaRef->Diag(D->getEllipsisLoc(), 
+                  diag::warn_gnu_array_range_designator_unsupported)
+      << SourceRange(D->getLBracketLoc(), D->getRBracketLoc());
   }
 
   bool ConstExpr 
@@ -581,28 +742,115 @@
     }
   }
   
+  // Make sure that our non-designated initializer list has space
+  // for a subobject corresponding to this array element.
+  unsigned ElementIndex = DesignatedIndex.getZExtValue();
+  if (ElementIndex >= StructuredList->getNumInits())
+    StructuredList->resizeInits(SemaRef->Context, ElementIndex + 1);
+
   // Recurse to check later designated subobjects.
   QualType ElementType = AT->getElementType();
-  if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index))
+  if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index,
+                                 StructuredList, ElementIndex))
     return true;
 
   // Move to the next index in the array that we'll be initializing.
   ++DesignatedIndex;
+  ElementIndex = DesignatedIndex.getZExtValue();
 
   // If this the first designator, our caller will continue checking
   // the rest of this array subobject.
   if (IsFirstDesignator) {
     if (NextElementIndex)
       *NextElementIndex = DesignatedIndex;
+    StructuredIndex = ElementIndex;
     return false;
   }
     
   // Check the remaining elements within this array subobject.
   bool prevHadError = hadError;
-  CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index);
+  CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index,
+                 StructuredList, ElementIndex);
   return hadError && !prevHadError;  
 }
 
+// Get the structured initializer list for a subobject of type
+// @p CurrentObjectType.
+InitListExpr *
+InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+                                            QualType CurrentObjectType,
+                                            InitListExpr *StructuredList,
+                                            unsigned StructuredIndex,
+                                            SourceRange InitRange) {
+  Expr *ExistingInit = 0;
+  if (!StructuredList)
+    ExistingInit = SyntacticToSemantic[IList];
+  else if (StructuredIndex < StructuredList->getNumInits())
+    ExistingInit = StructuredList->getInit(StructuredIndex);
+  
+  if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
+    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->getSourceRange().getBegin(), 
+                  diag::note_previous_initializer)
+      << ExistingInit->hasSideEffects(SemaRef->Context)
+      << ExistingInit->getSourceRange();
+  }
+
+  InitListExpr *Result 
+    = new (SemaRef->Context) InitListExpr(SourceLocation(), 0, 0, 
+                                          SourceLocation());
+  Result->setType(CurrentObjectType);
+
+  // Link this new initializer list into the structured initializer
+  // lists.
+  if (StructuredList)
+    StructuredList->updateInit(StructuredIndex, Result);
+  else {
+    Result->setSyntacticForm(IList);
+    SyntacticToSemantic[IList] = Result;
+  }
+
+  return Result;
+}
+
+/// Update the initializer at index @p StructuredIndex within the
+/// structured initializer list to the value @p expr.
+void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
+                                                  unsigned &StructuredIndex,
+                                                  Expr *expr) {
+  // No structured initializer list to update
+  if (!StructuredList)
+    return;
+
+  if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
+    // This initializer overwrites a previous initializer. Warn.
+    SemaRef->Diag(expr->getSourceRange().getBegin(), 
+                  diag::warn_initializer_overrides)
+      << expr->getSourceRange();
+    SemaRef->Diag(PrevInit->getSourceRange().getBegin(), 
+                  diag::note_previous_initializer)
+      << (int)PrevInit->hasSideEffects(SemaRef->Context)
+      << PrevInit->getSourceRange();
+  }
+  
+  ++StructuredIndex;
+}
+
 /// Check that the given Index expression is a valid array designator
 /// value. This is essentailly just a wrapper around
 /// Expr::isIntegerConstantExpr that also checks for negative values