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