Eliminate infinite looping in a wacky case with designated initializers. Simplifies (somewhat) the actually checking of the initializer expression following the designators

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63257 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 406eb26..ad21e7d 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1853,12 +1853,12 @@
                              InitListExpr *StructuredInitList,
                              unsigned &StructuredInitIndex);
   void CheckSubElementType(InitListExpr *IList, QualType ElemType, 
-                           Expr *expr, unsigned &Index,
+                           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,
+                       unsigned &Index,
                        InitListExpr *StructuredInitList,
                        unsigned &StructuredInitIndex);
   void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 66b938f..b78fc7b 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -188,7 +188,7 @@
                                             InitListExpr *StructuredList,
                                             unsigned &StructuredIndex) {
   if (DeclType->isScalarType()) {
-    CheckScalarType(IList, DeclType, 0, Index, StructuredList, StructuredIndex);
+    CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex);
   } else if (DeclType->isVectorType()) {
     CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
   } else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
@@ -221,10 +221,10 @@
 
 void InitListChecker::CheckSubElementType(InitListExpr *IList,
                                           QualType ElemType, 
-                                          Expr *expr,
                                           unsigned &Index,
                                           InitListExpr *StructuredList,
                                           unsigned &StructuredIndex) {
+  Expr *expr = IList->getInit(Index);
   if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
     unsigned newIndex = 0;
     unsigned newStructuredIndex = 0;
@@ -242,8 +242,7 @@
     UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
     ++Index;
   } else if (ElemType->isScalarType()) {
-    CheckScalarType(IList, ElemType, expr, Index, StructuredList, 
-                    StructuredIndex);
+    CheckScalarType(IList, ElemType, Index, StructuredList, StructuredIndex);
   } else if (expr->getType()->getAsRecordType() &&
              SemaRef->Context.typesAreCompatible(
                expr->getType().getUnqualifiedType(),
@@ -259,12 +258,11 @@
 }
 
 void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
-                                      Expr *expr, unsigned &Index,
+                                      unsigned &Index,
                                       InitListExpr *StructuredList,
                                       unsigned &StructuredIndex) {
   if (Index < IList->getNumInits()) {
-    if (!expr)
-      expr = IList->getInit(Index);
+    Expr *expr = IList->getInit(Index);
     if (isa<InitListExpr>(expr)) {
       SemaRef->Diag(IList->getLocStart(),
                     diag::err_many_braces_around_scalar_init)
@@ -288,12 +286,7 @@
       hadError = true; // types weren't compatible.
     else if (savExpr != expr) {
       // The type was promoted, update initializer list.
-      if (DesignatedInitExpr *DIE 
-            = dyn_cast<DesignatedInitExpr>(IList->getInit(Index)))
-        DIE->setInit(expr);
-      else
-        IList->setInit(Index, expr);
-
+      IList->setInit(Index, expr);
     }
     if (hadError)
       ++StructuredIndex;
@@ -323,7 +316,7 @@
       // 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, Index,
                           StructuredList, StructuredIndex);
     }
   }
@@ -417,7 +410,7 @@
       break;
 
     // Check this element.
-    CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
+    CheckSubElementType(IList, elementType, Index,
                         StructuredList, StructuredIndex);
     ++elementIndex;
 
@@ -498,7 +491,7 @@
       continue;
     }
 
-    CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index,
+    CheckSubElementType(IList, Field->getType(), Index,
                         StructuredList, StructuredIndex);
     if (DeclType->isUnionType())
       break;
@@ -559,8 +552,22 @@
   if (D == DIE->designators_end()) {
     // Check the actual initialization for the designated object type.
     bool prevHadError = hadError;
-    CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index,
+
+    // Temporarily remove the designator expression from the
+    // initializer list that the child calls see, so that we don't try
+    // to re-process the designator.
+    unsigned OldIndex = Index;
+    IList->setInit(OldIndex, DIE->getInit());
+
+    CheckSubElementType(IList, CurrentObjectType, Index,
                         StructuredList, StructuredIndex);
+
+    // Restore the designated initializer expression in the syntactic
+    // form of the initializer list.
+    if (IList->getInit(OldIndex) != DIE->getInit())
+      DIE->setInit(IList->getInit(OldIndex));
+    IList->setInit(OldIndex, DIE);
+
     return hadError && !prevHadError;
   }
 
diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
index db099dd..5c61faa 100644
--- a/test/Sema/designated-initializers.c
+++ b/test/Sema/designated-initializers.c
@@ -137,5 +137,13 @@
   };
 }
 
-// FIXME: we need to 
+// FIXME: How do we test that this initializes the long properly?
 union { char c; long l; } u1 = { .l = 0xFFFF };
+
+extern float global_float;
+
+struct XX { int a, *b; };
+struct XY { int before; struct XX xx, *xp; float* after; } xy[] = {
+  0, 0, &xy[0].xx.a, &xy[0].xx, &global_float,
+  [1].xx = 0, &xy[1].xx.a, &xy[1].xx, &global_float
+};