r262963 - P0017R1: In C++1z, an aggregate class can have (public non-virtual) base classes; these are initialized as if they were data members.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 8 14:17:42 PST 2016


Author: rsmith
Date: Tue Mar  8 16:17:41 2016
New Revision: 262963

URL: http://llvm.org/viewvc/llvm-project?rev=262963&view=rev
Log:
P0017R1: In C++1z, an aggregate class can have (public non-virtual) base classes; these are initialized as if they were data members.

Added:
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp
      - copied, changed from r262877, cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
    cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp
Removed:
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
Modified:
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Tue Mar  8 16:17:41 2016
@@ -284,9 +284,10 @@ public:
 
 
   /// \brief Create the initialization entity for a base class subobject.
-  static InitializedEntity InitializeBase(ASTContext &Context,
-                                          const CXXBaseSpecifier *Base,
-                                          bool IsInheritedVirtualBase);
+  static InitializedEntity
+  InitializeBase(ASTContext &Context, const CXXBaseSpecifier *Base,
+                 bool IsInheritedVirtualBase,
+                 const InitializedEntity *Parent = nullptr);
 
   /// \brief Create the initialization entity for a delegated constructor.
   static InitializedEntity InitializeDelegation(QualType Type) {

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Mar  8 16:17:41 2016
@@ -141,9 +141,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier
     C.Deallocate(data().getBases());
 
   if (NumBases) {
-    // C++ [dcl.init.aggr]p1:
-    //   An aggregate is [...] a class with [...] no base classes [...].
-    data().Aggregate = false;
+    if (!C.getLangOpts().CPlusPlus1z) {
+      // C++ [dcl.init.aggr]p1:
+      //   An aggregate is [...] a class with [...] no base classes [...].
+      data().Aggregate = false;
+    }
 
     // C++ [class]p4:
     //   A POD-struct is an aggregate class...
@@ -188,6 +190,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier
       data().HasNoNonEmptyBases = false;
     }
     
+    // C++1z [dcl.init.agg]p1:
+    //   An aggregate is a class with [...] no private or protected base classes
+    if (Base->getAccessSpecifier() != AS_public)
+      data().Aggregate = false;
+
     // C++ [class.virtual]p1:
     //   A class that declares or inherits a virtual function is called a 
     //   polymorphic class.
@@ -218,6 +225,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier
         if (CXXRecordDecl *VBaseDecl = VBase.getType()->getAsCXXRecordDecl())
           if (!VBaseDecl->hasCopyConstructorWithConstParam())
             data().ImplicitCopyConstructorHasConstParam = false;
+
+        // C++1z [dcl.init.agg]p1:
+        //   An aggregate is a class with [...] no virtual base classes
+        data().Aggregate = false;
       }
     }
 
@@ -226,11 +237,15 @@ CXXRecordDecl::setBases(CXXBaseSpecifier
       if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)).second)
         VBases.push_back(Base);
 
-      // C++0x [meta.unary.prop] is_empty:
+      // C++11 [meta.unary.prop] is_empty:
       //    T is a class type, but not a union type, with ... no virtual base
       //    classes
       data().Empty = false;
 
+      // C++1z [dcl.init.agg]p1:
+      //   An aggregate is a class with [...] no virtual base classes
+      data().Aggregate = false;
+
       // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
       //   A [default constructor, copy/move constructor, or copy/move assignment
       //   operator for a class X] is trivial [...] if:
@@ -732,7 +747,7 @@ void CXXRecordDecl::addedMember(Decl *D)
       //   An aggregate is a [...] class with [...] no
       //   brace-or-equal-initializers for non-static data members.
       //
-      // This rule was removed in C++1y.
+      // This rule was removed in C++14.
       if (!getASTContext().getLangOpts().CPlusPlus14)
         data().Aggregate = false;
 

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Mar  8 16:17:41 2016
@@ -5428,12 +5428,33 @@ bool RecordExprEvaluator::VisitInitListE
     return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
   }
 
-  assert((!isa<CXXRecordDecl>(RD) || !cast<CXXRecordDecl>(RD)->getNumBases()) &&
-         "initializer list for class with base classes");
-  Result = APValue(APValue::UninitStruct(), 0,
+  auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+  Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0,
                    std::distance(RD->field_begin(), RD->field_end()));
   unsigned ElementNo = 0;
   bool Success = true;
+
+  // Initialize base classes.
+  if (CXXRD) {
+    for (const auto &Base : CXXRD->bases()) {
+      assert(ElementNo < E->getNumInits() && "missing init for base class");
+      const Expr *Init = E->getInit(ElementNo);
+
+      LValue Subobject = This;
+      if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base))
+        return false;
+
+      APValue &FieldVal = Result.getStructBase(ElementNo);
+      if (!EvaluateInPlace(FieldVal, Info, Subobject, Init)) {
+        if (!Info.keepEvaluatingAfterFailure())
+          return false;
+        Success = false;
+      }
+      ++ElementNo;
+    }
+  }
+
+  // Initialize members.
   for (const auto *Field : RD->fields()) {
     // Anonymous bit-fields are not considered members of the class for
     // purposes of aggregate initialization.

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Mar  8 16:17:41 2016
@@ -1171,6 +1171,38 @@ void AggExprEmitter::VisitInitListExpr(I
   unsigned NumInitElements = E->getNumInits();
   RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl();
 
+  // We'll need to enter cleanup scopes in case any of the element
+  // initializers throws an exception.
+  SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
+  llvm::Instruction *cleanupDominator = nullptr;
+
+  unsigned curInitIndex = 0;
+
+  // Emit initialization of base classes.
+  if (auto *CXXRD = dyn_cast<CXXRecordDecl>(record)) {
+    assert(E->getNumInits() >= CXXRD->getNumBases() &&
+           "missing initializer for base class");
+    for (auto &Base : CXXRD->bases()) {
+      assert(!Base.isVirtual() && "should not see vbases here");
+      auto *BaseRD = Base.getType()->getAsCXXRecordDecl();
+      Address V = CGF.GetAddressOfDirectBaseInCompleteClass(
+          Dest.getAddress(), CXXRD, BaseRD,
+          /*isBaseVirtual*/ false);
+      AggValueSlot AggSlot =
+        AggValueSlot::forAddr(V, Qualifiers(),
+                              AggValueSlot::IsDestructed,
+                              AggValueSlot::DoesNotNeedGCBarriers,
+                              AggValueSlot::IsNotAliased);
+      CGF.EmitAggExpr(E->getInit(curInitIndex++), AggSlot);
+
+      if (QualType::DestructionKind dtorKind =
+              Base.getType().isDestructedType()) {
+        CGF.pushDestroy(dtorKind, V, Base.getType());
+        cleanups.push_back(CGF.EHStack.stable_begin());
+      }
+    }
+  }
+
   // Prepare a 'this' for CXXDefaultInitExprs.
   CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddress());
 
@@ -1204,14 +1236,8 @@ void AggExprEmitter::VisitInitListExpr(I
     return;
   }
 
-  // We'll need to enter cleanup scopes in case any of the member
-  // initializers throw an exception.
-  SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
-  llvm::Instruction *cleanupDominator = nullptr;
-
   // Here we iterate over the fields; this makes it simpler to both
   // default-initialize fields and skip over unnamed fields.
-  unsigned curInitIndex = 0;
   for (const auto *field : record->fields()) {
     // We're done once we hit the flexible array member.
     if (field->getType()->isIncompleteArrayType())
@@ -1317,6 +1343,10 @@ static CharUnits GetNumNonZeroBytesInIni
       CharUnits NumNonZeroBytes = CharUnits::Zero();
       
       unsigned ILEElement = 0;
+      if (auto *CXXRD = dyn_cast<CXXRecordDecl>(SD))
+        for (auto &Base : CXXRD->bases())
+          NumNonZeroBytes +=
+              GetNumNonZeroBytesInInit(ILE->getInit(ILEElement++), CGF);
       for (const auto *Field : SD->fields()) {
         // We're done once we hit the flexible array member or run out of
         // InitListExpr elements.

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Mar  8 16:17:41 2016
@@ -1011,15 +1011,18 @@ void CodeGenFunction::EmitNewArrayInitia
   if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
     if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
       if (RType->getDecl()->isStruct()) {
-        unsigned NumFields = 0;
+        unsigned NumElements = 0;
+        if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RType->getDecl()))
+          NumElements = CXXRD->getNumBases();
         for (auto *Field : RType->getDecl()->fields())
           if (!Field->isUnnamedBitfield())
-            ++NumFields;
-        if (ILE->getNumInits() == NumFields)
+            ++NumElements;
+        // FIXME: Recurse into nested InitListExprs.
+        if (ILE->getNumInits() == NumElements)
           for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
             if (!isa<ImplicitValueInitExpr>(ILE->getInit(i)))
-              --NumFields;
-        if (ILE->getNumInits() == NumFields && TryMemsetInitialization())
+              --NumElements;
+        if (ILE->getNumInits() == NumElements && TryMemsetInitialization())
           return;
       }
     }

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Tue Mar  8 16:17:41 2016
@@ -368,7 +368,14 @@ bool ConstStructBuilder::Build(InitListE
 
   unsigned FieldNo = 0;
   unsigned ElementNo = 0;
-  
+
+  // Bail out if we have base classes. We could support these, but they only
+  // arise in C++1z where we will have already constant folded most interesting
+  // cases. FIXME: There are still a few more cases we can handle this way.
+  if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+    if (CXXRD->getNumBases())
+      return false;
+
   for (RecordDecl::field_iterator Field = RD->field_begin(),
        FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
     // If this is a union, skip all the fields that aren't being initialized.
@@ -1124,6 +1131,13 @@ bool ConstStructBuilder::Build(ConstExpr
   unsigned FieldNo = -1;
   unsigned ElementNo = 0;
 
+  // Bail out if we have base classes. We could support these, but they only
+  // arise in C++1z where we will have already constant folded most interesting
+  // cases. FIXME: There are still a few more cases we can handle this way.
+  if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+    if (CXXRD->getNumBases())
+      return false;
+
   for (FieldDecl *Field : RD->fields()) {
     ++FieldNo;
 

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Mar  8 16:17:41 2016
@@ -282,6 +282,7 @@ class InitListChecker {
                        unsigned &StructuredIndex);
   void CheckStructUnionTypes(const InitializedEntity &Entity,
                              InitListExpr *IList, QualType DeclType,
+                             CXXRecordDecl::base_class_range Bases,
                              RecordDecl::field_iterator Field,
                              bool SubobjectIsDesignatorContext, unsigned &Index,
                              InitListExpr *StructuredList,
@@ -340,6 +341,10 @@ class InitListChecker {
   // in the InitListExpr, the "holes" in Case#1 are filled not with empty
   // initializers but with special "NoInitExpr" place holders, which tells the
   // CodeGen not to generate any initializers for these parts.
+  void FillInEmptyInitForBase(unsigned Init, const CXXBaseSpecifier &Base,
+                              const InitializedEntity &ParentEntity,
+                              InitListExpr *ILE, bool &RequiresSecondPass,
+                              bool FillWithNoInit);
   void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
                                const InitializedEntity &ParentEntity,
                                InitListExpr *ILE, bool &RequiresSecondPass,
@@ -479,6 +484,37 @@ void InitListChecker::CheckEmptyInitiali
     hadError = true;
 }
 
+void InitListChecker::FillInEmptyInitForBase(
+    unsigned Init, const CXXBaseSpecifier &Base,
+    const InitializedEntity &ParentEntity, InitListExpr *ILE,
+    bool &RequiresSecondPass, bool FillWithNoInit) {
+  assert(Init < ILE->getNumInits() && "should have been expanded");
+
+  InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
+      SemaRef.Context, &Base, false, &ParentEntity);
+
+  if (!ILE->getInit(Init)) {
+    ExprResult BaseInit =
+        FillWithNoInit ? new (SemaRef.Context) NoInitExpr(Base.getType())
+                       : PerformEmptyInit(SemaRef, ILE->getLocEnd(), BaseEntity,
+                                          /*VerifyOnly*/ false);
+    if (BaseInit.isInvalid()) {
+      hadError = true;
+      return;
+    }
+
+    ILE->setInit(Init, BaseInit.getAs<Expr>());
+  } else if (InitListExpr *InnerILE =
+                 dyn_cast<InitListExpr>(ILE->getInit(Init))) {
+    FillInEmptyInitializations(BaseEntity, InnerILE,
+                               RequiresSecondPass, FillWithNoInit);
+  } else if (DesignatedInitUpdateExpr *InnerDIUE =
+               dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
+    FillInEmptyInitializations(BaseEntity, InnerDIUE->getUpdater(),
+                               RequiresSecondPass, /*FillWithNoInit =*/true);
+  }
+}
+
 void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
                                         const InitializedEntity &ParentEntity,
                                               InitListExpr *ILE,
@@ -593,14 +629,25 @@ InitListChecker::FillInEmptyInitializati
       // The fields beyond ILE->getNumInits() are default initialized, so in
       // order to leave them uninitialized, the ILE is expanded and the extra
       // fields are then filled with NoInitExpr.
-      unsigned NumFields = 0;
-      for (auto *Field : RDecl->fields())
-        if (!Field->isUnnamedBitfield())
-          ++NumFields;
-      if (ILE->getNumInits() < NumFields)
-        ILE->resizeInits(SemaRef.Context, NumFields);
+      unsigned NumElems = numStructUnionElements(ILE->getType());
+      if (RDecl->hasFlexibleArrayMember())
+        ++NumElems;
+      if (ILE->getNumInits() < NumElems)
+        ILE->resizeInits(SemaRef.Context, NumElems);
 
       unsigned Init = 0;
+
+      if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RDecl)) {
+        for (auto &Base : CXXRD->bases()) {
+          if (hadError)
+            return;
+
+          FillInEmptyInitForBase(Init, Base, Entity, ILE, RequiresSecondPass,
+                                 FillWithNoInit);
+          ++Init;
+        }
+      }
+
       for (auto *Field : RDecl->fields()) {
         if (Field->isUnnamedBitfield())
           continue;
@@ -744,6 +791,8 @@ int InitListChecker::numArrayElements(Qu
 int InitListChecker::numStructUnionElements(QualType DeclType) {
   RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
   int InitializableMembers = 0;
+  if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl))
+    InitializableMembers += CXXRD->getNumBases();
   for (const auto *Field : structDecl->fields())
     if (!Field->isUnnamedBitfield())
       ++InitializableMembers;
@@ -991,10 +1040,14 @@ void InitListChecker::CheckListElementTy
     assert(DeclType->isAggregateType() &&
            "non-aggregate records should be handed in CheckSubElementType");
     RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
-    CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
-                          SubobjectIsDesignatorContext, Index,
-                          StructuredList, StructuredIndex,
-                          TopLevelObject);
+    auto Bases =
+        CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
+                                        CXXRecordDecl::base_class_iterator());
+    if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+      Bases = CXXRD->bases();
+    CheckStructUnionTypes(Entity, IList, DeclType, Bases, RD->field_begin(),
+                          SubobjectIsDesignatorContext, Index, StructuredList,
+                          StructuredIndex, TopLevelObject);
   } else if (DeclType->isArrayType()) {
     llvm::APSInt Zero(
                     SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
@@ -1670,16 +1723,13 @@ bool InitListChecker::CheckFlexibleArray
   return FlexArrayDiag != diag::ext_flexible_array_init;
 }
 
-void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
-                                            InitListExpr *IList,
-                                            QualType DeclType,
-                                            RecordDecl::field_iterator Field,
-                                            bool SubobjectIsDesignatorContext,
-                                            unsigned &Index,
-                                            InitListExpr *StructuredList,
-                                            unsigned &StructuredIndex,
-                                            bool TopLevelObject) {
-  RecordDecl* structDecl = DeclType->getAs<RecordType>()->getDecl();
+void InitListChecker::CheckStructUnionTypes(
+    const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
+    CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
+    bool SubobjectIsDesignatorContext, unsigned &Index,
+    InitListExpr *StructuredList, unsigned &StructuredIndex,
+    bool TopLevelObject) {
+  RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
 
   // If the record is invalid, some of it's members are invalid. To avoid
   // confusion, we forgo checking the intializer for the entire record.
@@ -1724,13 +1774,35 @@ void InitListChecker::CheckStructUnionTy
     return;
   }
 
+  bool InitializedSomething = false;
+
+  // If we have any base classes, they are initialized prior to the fields.
+  for (auto &Base : Bases) {
+    Expr *Init = Index < IList->getNumInits() ? IList->getInit(Index) : nullptr;
+    SourceLocation InitLoc = Init ? Init->getLocStart() : IList->getLocEnd();
+
+    // Designated inits always initialize fields, so if we see one, all
+    // remaining base classes have no explicit initializer.
+    if (Init && isa<DesignatedInitExpr>(Init))
+      Init = nullptr;
+
+    InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
+        SemaRef.Context, &Base, false, &Entity);
+    if (Init) {
+      CheckSubElementType(BaseEntity, IList, Base.getType(), Index,
+                          StructuredList, StructuredIndex);
+      InitializedSomething = true;
+    } else if (VerifyOnly) {
+      CheckEmptyInitializable(BaseEntity, InitLoc);
+    }
+  }
+
   // If structDecl is a forward declaration, this loop won't do
   // anything except look at designated initializers; That's okay,
   // because an error should get printed out elsewhere. It might be
   // worthwhile to skip over the rest of the initializer, though.
   RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
   RecordDecl::field_iterator FieldEnd = RD->field_end();
-  bool InitializedSomething = false;
   bool CheckForMissingFields = true;
   while (Index < IList->getNumInits()) {
     Expr *Init = IList->getInit(Index);
@@ -2302,8 +2374,11 @@ InitListChecker::CheckDesignatedInitiali
     // Check the remaining fields within this class/struct/union subobject.
     bool prevHadError = hadError;
 
-    CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index,
-                          StructuredList, FieldIndex);
+    auto NoBases =
+        CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
+                                        CXXRecordDecl::base_class_iterator());
+    CheckStructUnionTypes(Entity, IList, CurrentObjectType, NoBases, Field,
+                          false, Index, StructuredList, FieldIndex);
     return hadError && !prevHadError;
   }
 
@@ -2785,10 +2860,11 @@ InitializedEntity::InitializedEntity(AST
 InitializedEntity
 InitializedEntity::InitializeBase(ASTContext &Context,
                                   const CXXBaseSpecifier *Base,
-                                  bool IsInheritedVirtualBase) {
+                                  bool IsInheritedVirtualBase,
+                                  const InitializedEntity *Parent) {
   InitializedEntity Result;
   Result.Kind = EK_Base;
-  Result.Parent = nullptr;
+  Result.Parent = Parent;
   Result.Base = reinterpret_cast<uintptr_t>(Base);
   if (IsInheritedVirtualBase)
     Result.Base |= 0x01;
@@ -5778,6 +5854,11 @@ static const InitializedEntity *getEntit
                                                   FallbackDecl);
 
   case InitializedEntity::EK_Base:
+    // For subobjects, we look at the complete object.
+    if (Entity->getParent())
+      return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
+                                                    Entity);
+    // Fall through.
   case InitializedEntity::EK_Delegating:
     // We can reach this case for aggregate initialization in a constructor:
     //   struct A { int &&r; };

Removed: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp?rev=262962&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp (removed)
@@ -1,81 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y %s -DCXX1Y
-
-// An aggregate is an array or a class...
-struct Aggr {
-private:
-  static const int n;
-  void f();
-protected:
-  struct Inner { int m; };
-public:
-  bool &br; // expected-note {{default constructor of 'Aggr' is implicitly deleted because field 'br' of reference type 'bool &' would not be initialized}}
-};
-bool b;
-Aggr ag = { b };
-
-// with no user-provided constructors, ...
-struct NonAggr1a { // expected-note 2 {{candidate constructor}}
-  NonAggr1a(int, int); // expected-note {{candidate constructor}}
-  int k;
-};
-NonAggr1a na1a = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1a'}}
-
-struct NonAggr1b {
-  NonAggr1b(const NonAggr1b &); // expected-note {{candidate constructor}}
-  int k;
-};
-NonAggr1b na1b = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1b'}}
-
-// no brace-or-equal-initializers for non-static data members, ...
-// Note, this bullet was removed in C++1y.
-struct NonAggr2 {
-  int m = { 123 };
-};
-NonAggr2 na2 = { 42 };
-#ifndef CXX1Y
-// expected-error at -2 {{no matching constructor for initialization of 'NonAggr2'}}
-// expected-note at -6 3 {{candidate constructor}}
-#endif
-
-// no private...
-struct NonAggr3 { // expected-note 3 {{candidate constructor}}
-private:
-  int n;
-};
-NonAggr3 na3 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr3'}}
-
-// or protected non-static data members, ...
-struct NonAggr4 { // expected-note 3 {{candidate constructor}}
-protected:
-  int n;
-};
-NonAggr4 na4 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr4'}}
-
-// no base classes, ...
-struct NonAggr5 : Aggr { // expected-note 3 {{candidate constructor}}
-};
-NonAggr5 na5 = { b }; // expected-error {{no matching constructor for initialization of 'NonAggr5'}}
-template<typename...BaseList>
-struct MaybeAggr5a : BaseList... {}; // expected-note {{default constructor of 'MaybeAggr5a<Aggr>' is implicitly deleted because base class 'Aggr' has a deleted default constructor}}
-MaybeAggr5a<> ma5a0 = {}; // ok
-MaybeAggr5a<Aggr> ma5a1 = {}; // expected-error {{call to implicitly-deleted default constructor of 'MaybeAggr5a<Aggr>'}}
-
-// and no virtual functions.
-struct NonAggr6 { // expected-note 3 {{candidate constructor}}
-  virtual void f();
-  int n;
-};
-NonAggr6 na6 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr6'}}
-
-struct DefaultedAggr {
-  int n;
-
-  DefaultedAggr() = default;
-  DefaultedAggr(const DefaultedAggr &) = default;
-  DefaultedAggr(DefaultedAggr &&) = default;
-  DefaultedAggr &operator=(const DefaultedAggr &) = default;
-  DefaultedAggr &operator=(DefaultedAggr &&) = default;
-  ~DefaultedAggr() = default;
-};
-DefaultedAggr da = { 42 } ;

Copied: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp (from r262877, cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp?p2=cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp&p1=cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp&r1=262877&r2=262963&rev=262963&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1.cpp Tue Mar  8 16:17:41 2016
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y %s -DCXX1Y
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
 
 // An aggregate is an array or a class...
 struct Aggr {
@@ -9,7 +10,7 @@ private:
 protected:
   struct Inner { int m; };
 public:
-  bool &br; // expected-note {{default constructor of 'Aggr' is implicitly deleted because field 'br' of reference type 'bool &' would not be initialized}}
+  bool &br;
 };
 bool b;
 Aggr ag = { b };
@@ -33,7 +34,7 @@ struct NonAggr2 {
   int m = { 123 };
 };
 NonAggr2 na2 = { 42 };
-#ifndef CXX1Y
+#if __cplusplus < 201402L
 // expected-error at -2 {{no matching constructor for initialization of 'NonAggr2'}}
 // expected-note at -6 3 {{candidate constructor}}
 #endif
@@ -52,14 +53,56 @@ protected:
 };
 NonAggr4 na4 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr4'}}
 
-// no base classes, ...
-struct NonAggr5 : Aggr { // expected-note 3 {{candidate constructor}}
+// [pre-C++1z] no base classes, ...
+struct NonAggr5 : Aggr {
 };
-NonAggr5 na5 = { b }; // expected-error {{no matching constructor for initialization of 'NonAggr5'}}
+NonAggr5 na5 = { b };
+#if __cplusplus <= 201402L
+// expected-error at -2 {{no matching constructor for initialization of 'NonAggr5'}}
+// expected-note at -5 3 {{candidate constructor}}
+#endif
 template<typename...BaseList>
-struct MaybeAggr5a : BaseList... {}; // expected-note {{default constructor of 'MaybeAggr5a<Aggr>' is implicitly deleted because base class 'Aggr' has a deleted default constructor}}
+struct MaybeAggr5a : BaseList... {};
 MaybeAggr5a<> ma5a0 = {}; // ok
-MaybeAggr5a<Aggr> ma5a1 = {}; // expected-error {{call to implicitly-deleted default constructor of 'MaybeAggr5a<Aggr>'}}
+MaybeAggr5a<Aggr> ma5a1 = {}; // ok in C++17
+MaybeAggr5a<NonAggr2> m5a2 = {}; // ok, aggregate init in C++17, default ctor in C++11 and C++14
+MaybeAggr5a<NonAggr2> m5a3 = {0}; // ok in C++17, overrides default member initializer in base class
+#if __cplusplus <= 201402L
+// expected-error at -4 {{call to implicitly-deleted default constructor of 'MaybeAggr5a<Aggr>'}}
+// expected-note at -7 {{default constructor of 'MaybeAggr5a<Aggr>' is implicitly deleted because base class 'Aggr' has a deleted default constructor}}
+// expected-note at 13 {{default constructor of 'Aggr' is implicitly deleted because field 'br' of reference type 'bool &' would not be initialized}}
+// expected-error at -5 {{no matching constructor}} expected-note at -9 3{{candidate}}
+#else
+// expected-error at -9 {{reference member of type 'bool &' uninitialized}}
+// expected-note at 13 {{uninitialized reference member is here}}
+#endif
+
+// [C++1z] no virtual, protected, or private base classes, ...
+struct NonAggr5b : virtual Aggr {}; // expected-note 3{{candidate}}
+NonAggr5b na5b = { b }; // expected-error {{no matching constructor}}
+struct NonAggr5c : NonAggr5b {}; // expected-note 3{{candidate}}
+NonAggr5c na5c = { b }; // expected-error {{no matching constructor}}
+struct NonAggr5d : protected Aggr {}; // expected-note 3{{candidate}}
+NonAggr5d na5d = { b }; // expected-error {{no matching constructor}}
+struct NonAggr5e : private Aggr {}; // expected-note 3{{candidate}}
+NonAggr5e na5e = { b }; // expected-error {{no matching constructor}}
+class NonAggr5f : Aggr {}; // expected-note 3{{candidate}}
+NonAggr5f na5f = { b }; // expected-error {{no matching constructor}}
+
+// [C++1z] (the base class need not itself be an aggregate)
+struct MaybeAggr5g : NonAggr1a {};
+MaybeAggr5g ma5g1 = { 1 };
+MaybeAggr5g ma5g2 = { {1, 2} };
+MaybeAggr5g ma5g3 = {};
+#if __cplusplus <= 201402L
+// expected-error at -4 {{no matching constructor}} // expected-note at -5 3{{candidate}}
+// expected-error at -4 {{no matching constructor}} // expected-note at -6 3{{candidate}}
+// expected-error at -4 {{implicitly-deleted default constructor}} expected-note at -7 {{no default constructor}}
+#else
+// expected-error at -8 {{no viable conversion from 'int' to 'NonAggr1a'}} expected-note at 19 2{{candidate}}
+// (ok)
+// expected-error at -8 {{no matching constructor}} expected-note at 19 2{{candidate}} expected-note at 20 {{candidate}}
+#endif
 
 // and no virtual functions.
 struct NonAggr6 { // expected-note 3 {{candidate constructor}}

Added: cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp?rev=262963&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx1z-initializer-aggregate.cpp Tue Mar  8 16:17:41 2016
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -std=c++1z %s -triple x86_64-linux-gnu -fexceptions -fcxx-exceptions -emit-llvm -o - | FileCheck %s
+
+namespace Constant {
+  struct A {
+    int n;
+    char k;
+    ~A();
+  };
+
+  struct B {
+    char k2;
+  };
+
+  struct C : B {};
+
+  struct D : A, C {};
+
+  C c1 = {};
+  C c2 = {1};
+  // CHECK: @_ZN8Constant2c1E = global { i8 } zeroinitializer, align 1
+  // CHECK: @_ZN8Constant2c2E = global { i8 } { i8 1 }, align 1
+
+  // Test packing bases into tail padding.
+  D d1 = {};
+  D d2 = {1, 2, 3};
+  D d3 = {1};
+  // CHECK: @_ZN8Constant2d1E = global { i32, i8, i8 } zeroinitializer, align 4
+  // CHECK: @_ZN8Constant2d2E = global { i32, i8, i8 } { i32 1, i8 2, i8 3 }, align 4
+  // CHECK: @_ZN8Constant2d3E = global { i32, i8, i8 } { i32 1, i8 0, i8 0 }, align 4
+
+  // CHECK-LABEL: define {{.*}}global_var_init
+  // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN8Constant1DD1Ev {{.*}} @_ZN8Constant2d1E
+
+  // CHECK-LABEL: define {{.*}}global_var_init
+  // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN8Constant1DD1Ev {{.*}} @_ZN8Constant2d2E
+
+  // CHECK-LABEL: define {{.*}}global_var_init
+  // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN8Constant1DD1Ev {{.*}} @_ZN8Constant2d3E
+}
+
+namespace Dynamic {
+  struct A {
+    A();
+    A(int);
+    A(const char*, unsigned);
+    ~A();
+    void *p;
+  };
+
+  struct B {
+    ~B();
+    int n = 5;
+  };
+
+  struct C {
+    C(bool = true);
+  };
+
+  int f(), g(), h(), i();
+  struct D : A, B, C {
+    int n = f();
+  };
+
+  D d1 = {};
+  // CHECK-LABEL: define {{.*}}global_var_init
+  // CHECK: call void @_ZN7Dynamic1AC2Ev({{.*}} @_ZN7Dynamic2d1E
+  // CHECK: store i32 5, {{.*}}i8* getelementptr inbounds {{.*}} @_ZN7Dynamic2d1E{{.*}}, i64 8
+  // CHECK: invoke void @_ZN7Dynamic1CC2Eb({{.*}} @_ZN7Dynamic2d1E{{.*}}, i1 zeroext true)
+  // CHECK:   unwind label %[[UNWIND:.*]]
+  // CHECK: invoke i32 @_ZN7Dynamic1fEv()
+  // CHECK:   unwind label %[[UNWIND:.*]]
+  // CHECK: store i32 {{.*}}, i32* getelementptr {{.*}} @_ZN7Dynamic2d1E, i32 0, i32 2
+  // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN7Dynamic1DD1Ev {{.*}} @_ZN7Dynamic2d1E
+  // CHECK: ret
+  //
+  //   UNWIND:
+  // CHECK: call void @_ZN7Dynamic1BD1Ev({{.*}}i8* getelementptr inbounds {{.*}} @_ZN7Dynamic2d1E{{.*}}, i64 8
+  // CHECK: call void @_ZN7Dynamic1AD1Ev({{.*}} @_ZN7Dynamic2d1E
+
+  D d2 = {1, 2, false};
+  // CHECK-LABEL: define {{.*}}global_var_init
+  // CHECK: call void @_ZN7Dynamic1AC1Ei({{.*}} @_ZN7Dynamic2d2E{{.*}}, i32 1)
+  // CHECK: store i32 2, {{.*}}i8* getelementptr inbounds {{.*}}@_ZN7Dynamic2d2E{{.*}}, i64 8
+  // CHECK: invoke void @_ZN7Dynamic1CC1Eb({{.*}} @_ZN7Dynamic2d2E{{.*}}, i1 zeroext false)
+  // CHECK: invoke i32 @_ZN7Dynamic1fEv()
+  // CHECK: store i32 {{.*}}, i32* getelementptr {{.*}} @_ZN7Dynamic2d2E, i32 0, i32 2
+  // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN7Dynamic1DD1Ev {{.*}} @_ZN7Dynamic2d2E
+  // CHECK: ret void
+
+  D d3 = {g(), h(), {}, i()};
+  // CHECK-LABEL: define {{.*}}global_var_init
+  // CHECK: %[[G_CALL:.*]] = call i32 @_ZN7Dynamic1gEv()
+  // CHECK: call void @_ZN7Dynamic1AC1Ei({{.*}} @_ZN7Dynamic2d3E{{.*}}, i32 %[[G_CALL]])
+  // CHECK: %[[H_CALL:.*]] = invoke i32 @_ZN7Dynamic1hEv()
+  // CHECK:   unwind label %[[DESTROY_A_LPAD:.*]]
+  // CHECK: store i32 %[[H_CALL]], {{.*}}i8* getelementptr inbounds {{.*}} @_ZN7Dynamic2d3E{{.*}}, i64 8
+  // CHECK: invoke void @_ZN7Dynamic1CC2Eb({{.*}} @_ZN7Dynamic2d3E{{.*}}, i1 zeroext true)
+  // CHECK:   unwind label %[[DESTROY_AB_LPAD:.*]]
+  // CHECK: %[[I_CALL:.*]] = invoke i32 @_ZN7Dynamic1iEv()
+  // CHECK:   unwind label %[[DESTROY_AB_LPAD:.*]]
+  // CHECK: store i32 %[[I_CALL]], i32* getelementptr {{.*}} @_ZN7Dynamic2d3E, i32 0, i32 2
+  // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN7Dynamic1DD1Ev {{.*}} @_ZN7Dynamic2d3E to i8*
+  // CHECK: ret
+  //
+  //   DESTROY_A_LPAD:
+  // CHECK: br label %[[A_CLEANUP:.*]]
+  //
+  //   DESTROY_B_LPAD:
+  // CHECK: call void @_ZN7Dynamic1BD1Ev({{.*}}i8* getelementptr inbounds {{.*}} @_ZN7Dynamic2d3E{{.*}}, i64 8
+  // CHECK: br label %[[A_CLEANUP:.*]]
+  //
+  //   A_CLEANUP:
+  // CHECK: call void @_ZN7Dynamic1AD1Ev({{.*}} @_ZN7Dynamic2d3E
+}

Added: cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp?rev=262963&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp (added)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp Tue Mar  8 16:17:41 2016
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
+
+namespace BaseClassAggregateInit {
+  struct A {
+    int a, b, c;
+    constexpr A(int n) : a(n), b(3 * n), c(b - 1) {} // expected-note {{outside the range of representable}}
+    constexpr A() : A(10) {};
+  };
+  struct B : A {};
+  struct C { int q; };
+  struct D : B, C { int k; };
+
+  constexpr D d1 = { 1, 2, 3 };
+  static_assert(d1.a == 1 && d1.b == 3 && d1.c == 2 && d1.q == 2 && d1.k == 3);
+
+  constexpr D d2 = { 14 };
+  static_assert(d2.a == 14 && d2.b == 42 && d2.c == 41 && d2.q == 0 && d2.k == 0);
+
+  constexpr D d3 = { A(5), C{2}, 1 };
+  static_assert(d3.a == 5 && d3.b == 15 && d3.c == 14 && d3.q == 2 && d3.k == 1);
+
+  constexpr D d4 = {};
+  static_assert(d4.a == 10 && d4.b == 30 && d4.c == 29 && d4.q == 0 && d4.k == 0);
+
+  constexpr D d5 = { __INT_MAX__ }; // expected-error {{must be initialized by a constant expression}}
+  // expected-note-re at -1 {{in call to 'A({{.*}})'}}
+}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=262963&r1=262962&r2=262963&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Tue Mar  8 16:17:41 2016
@@ -644,7 +644,7 @@ as the draft C++1z standard evolves.</p>
     <tr>
       <td>Aggregate initialization of classes with base classes</td>
       <td><a href="http://wg21.link/p0017r1">P0017R1</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td><tt>constexpr</tt> lambda expressions</td>




More information about the cfe-commits mailing list