Implement and test aggregate initialization in C++. Major changes:

  - Support initialization of reference members; complain if any
  reference members are left uninitialized.
  - Use C++ copy-initialization for initializing each element (falls
  back to constraint checking in C)
  - Make sure we diagnose when one tries to provide an initializer
  list for a non-aggregate.
  - Don't complain about empty initializers in C++ (they are permitted)
  - Unrelated but necessary: don't bother trying to convert the
  decl-specifier-seq to a type when we're dealing with a C++
  constructor, destructor, or conversion operator; it results in
  spurious warnings.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63431 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 3395313..5dd45fb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1074,23 +1074,7 @@
         << Init->getSourceRange();
 
     return CheckSingleInitializer(Init, DeclType, DirectInit);
-  } else if (getLangOptions().CPlusPlus) {
-    // C++ [dcl.init]p14:
-    //   [...] If the class is an aggregate (8.5.1), and the initializer
-    //   is a brace-enclosed list, see 8.5.1.
-    //
-    // Note: 8.5.1 is handled below; here, we diagnose the case where
-    // we have an initializer list and a destination type that is not
-    // an aggregate.
-    // FIXME: In C++0x, this is yet another form of initialization.
-    // FIXME: Move this checking into CheckInitList!
-    if (const RecordType *ClassRec = DeclType->getAsRecordType()) {
-      const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
-      if (!ClassDecl->isAggregate())
-        return Diag(InitLoc, diag::err_init_non_aggr_init_list)
-           << DeclType << Init->getSourceRange();
-    }
-  }
+  } 
 
   bool hadError = CheckInitList(InitList, DeclType);
   Init = InitList;
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index ed44acf..5d40e43 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -69,11 +69,14 @@
                            unsigned &Index,
                            InitListExpr *StructuredList,
                            unsigned &StructuredIndex);
-  // FIXME: Does DeclType need to be a reference type?
-  void CheckScalarType(InitListExpr *IList, QualType &DeclType, 
+  void CheckScalarType(InitListExpr *IList, QualType DeclType, 
                        unsigned &Index,
                        InitListExpr *StructuredList,
                        unsigned &StructuredIndex);
+  void CheckReferenceType(InitListExpr *IList, QualType DeclType, 
+                          unsigned &Index,
+                          InitListExpr *StructuredList,
+                          unsigned &StructuredIndex);
   void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
                        InitListExpr *StructuredList,
                        unsigned &StructuredIndex);
@@ -106,6 +109,8 @@
                                    Expr *expr);
   int numArrayElements(QualType DeclType);
   int numStructUnionElements(QualType DeclType);
+
+  void FillInValueInitializations(InitListExpr *ILE);
 public:
   InitListChecker(Sema *S, InitListExpr *IL, QualType &T);
   bool HadError() { return hadError; }
@@ -116,12 +121,12 @@
 };
 }
 
-
 /// 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");
+void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
+  assert((ILE->getType() != SemaRef->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(),
@@ -130,17 +135,31 @@
       if (Field->isUnnamedBitfield())
         continue;
 
-      if (Init >= NumInits)
-        break;
-
-      // FIXME: Check for fields with reference type in C++?
-      if (!ILE->getInit(Init))
+      if (Init >= NumInits) {
+        if (Field->getType()->isReferenceType()) {
+          // C++ [dcl.init.aggr]p9:
+          //   If an incomplete or empty initializer-list leaves a
+          //   member of reference type uninitialized, the program is
+          //   ill-formed. 
+          SemaRef->Diag(ILE->getSyntacticForm()->getLocStart(), 
+                        diag::err_init_reference_member_uninitialized)
+            << Field->getType()
+            << ILE->getSyntacticForm()->getSourceRange();
+          SemaRef->Diag(Field->getLocation(), 
+                        diag::note_uninit_reference_member);
+          hadError = true;
+        }
+      } else if (!ILE->getInit(Init))
         ILE->setInit(Init, 
-                     new (Context) ImplicitValueInitExpr(Field->getType()));
+                new (SemaRef->Context) ImplicitValueInitExpr(Field->getType()));
       else if (InitListExpr *InnerILE 
                  = dyn_cast<InitListExpr>(ILE->getInit(Init)))
-        fillInValueInitializations(Context, InnerILE);
+        FillInValueInitializations(InnerILE);
       ++Init;
+
+      // Only look at the first initialization of a union.
+      if (RType->getDecl()->isUnion())
+        break;
     }
 
     return;
@@ -148,7 +167,7 @@
 
   QualType ElementType;
   
-  if (const ArrayType *AType = Context.getAsArrayType(ILE->getType()))
+  if (const ArrayType *AType = SemaRef->Context.getAsArrayType(ILE->getType()))
     ElementType = AType->getElementType();
   else if (const VectorType *VType = ILE->getType()->getAsVectorType())
     ElementType = VType->getElementType();
@@ -158,9 +177,10 @@
   for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits; 
        ++Init) {
     if (!ILE->getInit(Init))
-      ILE->setInit(Init, new (Context) ImplicitValueInitExpr(ElementType));
+      ILE->setInit(Init, 
+                   new (SemaRef->Context) ImplicitValueInitExpr(ElementType));
     else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init)))
-      fillInValueInitializations(Context, InnerILE);
+      FillInValueInitializations(InnerILE);
   }
 }
 
@@ -175,9 +195,8 @@
     = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange());
   CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex);
 
-  if (!hadError) {
-    fillInValueInitializations(SemaRef->Context, FullyStructuredList);
-  }
+  if (!hadError)
+    FillInValueInitializations(FullyStructuredList);
 }
 
 int InitListChecker::numArrayElements(QualType DeclType) {
@@ -219,7 +238,6 @@
   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);
@@ -308,6 +326,20 @@
     SemaRef->Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
       << DeclType;
     hadError = true;
+  } else if (DeclType->isRecordType()) {
+    // C++ [dcl.init]p14:
+    //   [...] If the class is an aggregate (8.5.1), and the initializer
+    //   is a brace-enclosed list, see 8.5.1.
+    //
+    // Note: 8.5.1 is handled below; here, we diagnose the case where
+    // we have an initializer list and a destination type that is not
+    // an aggregate.
+    // FIXME: In C++0x, this is yet another form of initialization.
+    SemaRef->Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
+      << DeclType << IList->getSourceRange();
+    hadError = true;
+  } else if (DeclType->isReferenceType()) {
+    CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex);
   } else {
     // In C, all types are either scalars or aggregates, but
     // additional handling is needed here for C++ (and possibly others?). 
@@ -339,21 +371,70 @@
     ++Index;
   } else if (ElemType->isScalarType()) {
     CheckScalarType(IList, ElemType, Index, StructuredList, StructuredIndex);
-  } else if (expr->getType()->getAsRecordType() &&
-             SemaRef->Context.typesAreCompatible(
-               expr->getType().getUnqualifiedType(),
-               ElemType.getUnqualifiedType())) {
-    UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
-    ++Index;
-    // FIXME: Add checking
+  } else if (ElemType->isReferenceType()) {
+    CheckReferenceType(IList, ElemType, Index, StructuredList, StructuredIndex);
   } else {
-    CheckImplicitInitList(IList, ElemType, Index, StructuredList, 
-                          StructuredIndex);
-    ++StructuredIndex;
- }
+    if (SemaRef->getLangOptions().CPlusPlus) {
+      // C++ [dcl.init.aggr]p12:
+      //   All implicit type conversions (clause 4) are considered when
+      //   initializing the aggregate member with an ini- tializer from
+      //   an initializer-list. If the initializer can initialize a
+      //   member, the member is initialized. [...]
+      ImplicitConversionSequence ICS 
+        = SemaRef->TryCopyInitialization(expr, ElemType);
+      if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) {
+        if (SemaRef->PerformImplicitConversion(expr, ElemType, ICS, 
+                                               "initializing"))
+          hadError = true;
+        UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+        ++Index;
+        return;
+      }
+
+      // Fall through for subaggregate initialization
+    } else {
+      // C99 6.7.8p13: 
+      //
+      //   The initializer for a structure or union object that has
+      //   automatic storage duration shall be either an initializer
+      //   list as described below, or a single expression that has
+      //   compatible structure or union type. In the latter case, the
+      //   initial value of the object, including unnamed members, is
+      //   that of the expression.
+      QualType ExprType = SemaRef->Context.getCanonicalType(expr->getType());
+      QualType ElemTypeCanon = SemaRef->Context.getCanonicalType(ElemType);
+      if (SemaRef->Context.typesAreCompatible(ExprType.getUnqualifiedType(),
+                                          ElemTypeCanon.getUnqualifiedType())) {
+        UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+        ++Index;
+        return;
+      }
+
+      // Fall through for subaggregate initialization
+    }
+
+    // C++ [dcl.init.aggr]p12:
+    // 
+    //   [...] Otherwise, if the member is itself a non-empty
+    //   subaggregate, brace elision is assumed and the initializer is
+    //   considered for the initialization of the first member of
+    //   the subaggregate.
+    if (ElemType->isAggregateType() || ElemType->isVectorType()) {
+      CheckImplicitInitList(IList, ElemType, Index, StructuredList, 
+                            StructuredIndex);
+      ++StructuredIndex;
+    } else {
+      // We cannot initialize this element, so let
+      // PerformCopyInitialization produce the appropriate diagnostic.
+      SemaRef->PerformCopyInitialization(expr, ElemType, "initializing");
+      hadError = true;
+      ++Index;
+      ++StructuredIndex;
+    }
+  }
 }
 
-void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
+void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
                                       unsigned &Index,
                                       InitListExpr *StructuredList,
                                       unsigned &StructuredIndex) {
@@ -399,6 +480,49 @@
   }
 }
 
+void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
+                                         unsigned &Index,
+                                         InitListExpr *StructuredList,
+                                         unsigned &StructuredIndex) {
+  if (Index < IList->getNumInits()) {
+    Expr *expr = IList->getInit(Index);
+    if (isa<InitListExpr>(expr)) {
+      SemaRef->Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
+        << DeclType << IList->getSourceRange();
+      hadError = true;
+      ++Index;
+      ++StructuredIndex;
+      return;
+    } 
+
+    Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
+    if (SemaRef->CheckReferenceInit(expr, DeclType))
+      hadError = true;
+    else if (savExpr != expr) {
+      // The type was promoted, update initializer list.
+      IList->setInit(Index, expr);
+    }
+    if (hadError)
+      ++StructuredIndex;
+    else
+      UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+    ++Index;
+  } else {
+    // FIXME: It would be wonderful if we could point at the actual
+    // member. In general, it would be useful to pass location
+    // information down the stack, so that we know the location (or
+    // decl) of the "current object" being initialized.
+    SemaRef->Diag(IList->getLocStart(), 
+                  diag::err_init_reference_member_uninitialized)
+      << DeclType
+      << IList->getSourceRange();
+    hadError = true;
+    ++Index;
+    ++StructuredIndex;
+    return;
+  }
+}
+
 void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, 
                                       unsigned &Index,
                                       InitListExpr *StructuredList,
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 43f8baa..9d78d0a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -18,8 +18,11 @@
 #include "clang/Parse/DeclSpec.h"
 using namespace clang;
 
-/// ConvertDeclSpecToType - Convert the specified declspec to the appropriate
-/// type object.  This returns null on error.
+/// \brief Convert the specified declspec to the appropriate type
+/// object.
+/// \param DS  the declaration specifiers
+/// \returns The type described by the declaration specifiers, or NULL
+/// if there was an error.
 QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) {
   // FIXME: Should move the logic from DeclSpec::Finish to here for validity
   // checking.
@@ -81,6 +84,7 @@
       // "At least one type specifier shall be given in the declaration
       // specifiers in each declaration, and in the specifier-qualifier list in
       // each struct declaration and type name."
+      // FIXME: this should be a hard error in C++
       if (!DS.hasTypeSpecifier())
         Diag(DS.getSourceRange().getBegin(), diag::ext_missing_type_specifier);
     }
@@ -254,8 +258,26 @@
   if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
       D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
     Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong);
-  
-  QualType T = ConvertDeclSpecToType(D.getDeclSpec());
+
+  // Determine the type of the declarator. Not all forms of declarator
+  // have a type.
+  QualType T;
+  switch (D.getKind()) {
+  case Declarator::DK_Abstract:
+  case Declarator::DK_Normal:
+  case Declarator::DK_Operator:
+    T = ConvertDeclSpecToType(D.getDeclSpec());
+    break;
+
+  case Declarator::DK_Constructor:
+  case Declarator::DK_Destructor:
+  case Declarator::DK_Conversion:
+    // Constructors and destructors don't have return types. Use
+    // "void" instead. Conversion operators will check their return
+    // types separately.
+    T = Context.VoidTy;
+    break;
+  }
 
   // Walk the DeclTypeInfo, building the recursive type as we go.  DeclTypeInfos
   // are ordered from the identifier out, which is opposite of what we want :).