[cfe-commits] r63431 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Parse/ParseInit.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaType.cpp test/SemaCXX/dcl_init_aggr.cpp www/cxx_status.html

Douglas Gregor dgregor at apple.com
Fri Jan 30 14:09:00 PST 2009


Author: dgregor
Date: Fri Jan 30 16:09:00 2009
New Revision: 63431

URL: http://llvm.org/viewvc/llvm-project?rev=63431&view=rev
Log:
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.

Added:
    cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/lib/Parse/ParseInit.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=63431&r1=63430&r2=63431&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Fri Jan 30 16:09:00 2009
@@ -270,6 +270,10 @@
      "declaration of const variable '%0' requires an initializer")
 DIAG(err_init_non_aggr_init_list, ERROR,
      "initialization of non-aggregate type %0 with an initializer list")
+DIAG(err_init_reference_member_uninitialized, ERROR,
+     "reference member of type %0 uninitialized")
+DIAG(note_uninit_reference_member, NOTE,
+     "uninitialized reference member is here")
 
 // Objective-C++
 DIAG(err_objc_decls_may_only_appear_in_global_scope, ERROR,

Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=63431&r1=63430&r2=63431&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Fri Jan 30 16:09:00 2009
@@ -256,10 +256,10 @@
   /// was specified for it, if any.
   InitListDesignations InitExprDesignations(Actions);
 
-  // We support empty initializers, but tell the user that they aren't using
-  // C99-clean code.
   if (Tok.is(tok::r_brace)) {
-    Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
+    // Empty initializers are a C++ feature and a GNU extension to C.
+    if (!getLang().CPlusPlus)
+      Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
     // Match the '}'.
     return Actions.ActOnInitList(LBraceLoc, Action::MultiExprArg(Actions),
                                  InitExprDesignations, ConsumeBrace());

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=63431&r1=63430&r2=63431&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jan 30 16:09:00 2009
@@ -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;

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=63431&r1=63430&r2=63431&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Jan 30 16:09:00 2009
@@ -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,

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=63431&r1=63430&r2=63431&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Jan 30 16:09:00 2009
@@ -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 :).

Added: cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp?rev=63431&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp (added)
+++ cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp Fri Jan 30 16:09:00 2009
@@ -0,0 +1,107 @@
+// RUN: clang -fsyntax-only -pedantic -verify %s
+// C++ [dcl.init.aggr]p2
+struct A { 
+  int x;
+  struct B { 
+    int i;
+    int j;
+  } b; 
+} a1 = { 1, { 2, 3 } };
+
+struct NonAggregate {
+  NonAggregate();
+
+  int a, b;
+};
+NonAggregate non_aggregate_test = { 1, 2 }; // expected-error{{initialization of non-aggregate type 'struct NonAggregate' with an initializer list}}
+
+NonAggregate non_aggregate_test2[2] = { { 1, 2 }, { 3, 4 } }; // expected-error{{initialization of non-aggregate type 'struct NonAggregate' with an initializer list}}
+
+
+// C++ [dcl.init.aggr]p3
+A a_init = A(); 
+
+// C++ [dcl.init.aggr]p4
+int x[] = { 1, 3, 5 };
+int x_sizecheck[(sizeof(x) / sizeof(int)) == 3? 1 : -1];
+int x2[] = { }; // expected-warning{{zero size arrays are an extension}}
+
+// C++ [dcl.init.aggr]p5
+struct StaticMemberTest {
+  int i;
+  static int s;
+  int *j;
+} smt = { 1, &smt.i };
+
+// C++ [dcl.init.aggr]p6
+char cv[4] = { 'a', 's', 'd', 'f', 0 }; // expected-warning{{excess elements in array initializer}}
+
+// C++ [dcl.init.aggr]p7
+struct TooFew { int a; char* b; int c; }; 
+TooFew too_few = { 1, "asdf" }; // okay
+
+// C++ [dcl.init.aggr]p8
+struct Empty { };
+struct EmptyTest {
+  Empty s;
+  int i;
+} empty_test = { { }, 3 };
+
+EmptyTest empty_test2 = { 3 }; // expected-error{{initializer for aggregate with no elements requires explicit braces}}
+
+struct NonEmpty { 
+  int a;
+  Empty empty;
+};
+struct NonEmptyTest {
+  NonEmpty a, b;
+} non_empty_test = { { }, { } };
+
+// C++ [dcl.init.aggr]p9
+struct HasReference {
+  int i;
+  int &j; // expected-note{{uninitialized reference member is here}}
+};
+int global_int;
+HasReference r1 = { 1, global_int };
+HasReference r2 = { 1 } ; // expected-error{{initialization leaves reference member of type 'int &' uninitialized}}
+
+// C++ [dcl.init.aggr]p10
+// Note: the behavior here is identical to C
+int xs[2][2] = { 3, 1, 4, 2 };
+float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } };
+
+// C++ [dcl.init.aggr]p11
+// Note: the behavior here is identical to C
+float y2[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 } };
+float same_as_y2[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
+
+// C++ [dcl.init.aggr]p12
+struct A2 { 
+  int i;
+  operator int *();
+}; 
+struct B2 {
+  A2 a1, a2; 
+  int *z;
+}; 
+struct C2 {
+  operator A2();
+};
+struct D2 {
+  operator int();
+};
+A2 a2;
+C2 c2; 
+D2 d2;
+B2 b2 = { 4, a2, a2 };
+B2 b2_2 = { 4, d2, 0 };
+// FIXME: B2 b2_3 = { c2, a2, a2 };
+
+// C++ [dcl.init.aggr]p15:
+union u { int a; char* b; };
+u u1 = { 1 }; 
+u u2 = u1; 
+u u3 = 1; // expected-error{{cannot initialize 'u3' with an rvalue of type 'int'}}
+u u4 = { 0, "asdf" };  // expected-warning{{excess elements in array initializer}}
+u u5 = { "asdf" }; // expected-error{{incompatible type initializing 'char const [5]', expected 'int'}}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=63431&r1=63430&r2=63431&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Fri Jan 30 16:09:00 2009
@@ -999,7 +999,14 @@
 </tr>
 <tr><td>  8.4 [dcl.fct.def]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  8.5 [dcl.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>    8.5.1 [dcl.init.aggr]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>    8.5.1[dcl.init.aggr]</td>
+  <td class="advanced" align="center"></td>
+  <td class="advanced" align="center"></td>
+  <td class="medium" align="center"></td>
+  <td class="basic" align="center"></td>
+  <td>No CodeGen for initializing non-aggregates or dynamic initialization.</td>
+</tr>
 <tr><td>    8.5.2 [dcl.init.string]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr>
   <td>    8.5.3 [dcl.init.ref]</td>





More information about the cfe-commits mailing list