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

llvm-svn: 262963
This commit is contained in:
Richard Smith 2016-03-08 22:17:41 +00:00
parent a99000dd31
commit 872307e2ac
12 changed files with 479 additions and 130 deletions

View File

@ -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) {

View File

@ -141,9 +141,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
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 const * const *Bases,
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 const * const *Bases,
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 const * const *Bases,
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;

View File

@ -5428,12 +5428,33 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
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.

View File

@ -1171,6 +1171,38 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
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(InitListExpr *E) {
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 GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
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.

View File

@ -1011,15 +1011,18 @@ void CodeGenFunction::EmitNewArrayInitializer(
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;
}
}

View File

@ -368,7 +368,14 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
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(ConstExprEmitter *Emitter,
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;

View File

@ -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::CheckEmptyInitializable(const InitializedEntity &Entity,
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::FillInEmptyInitializations(const InitializedEntity &Entity,
// 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(QualType DeclType) {
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::CheckListElementTypes(const InitializedEntity &Entity,
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::CheckFlexibleArrayInit(const InitializedEntity &Entity,
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::CheckStructUnionTypes(const InitializedEntity &Entity,
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::CheckDesignatedInitializer(const InitializedEntity &Entity,
// 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(ASTContext &Context, unsigned Index,
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 *getEntityForTemporaryLifetimeExtension(
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; };

View File

@ -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@-2 {{no matching constructor for initialization of 'NonAggr2'}}
// expected-note@-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 } ;

View File

@ -0,0 +1,124 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// 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 {
private:
static const int n;
void f();
protected:
struct Inner { int m; };
public:
bool &br;
};
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 };
#if __cplusplus < 201402L
// expected-error@-2 {{no matching constructor for initialization of 'NonAggr2'}}
// expected-note@-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'}}
// [pre-C++1z] no base classes, ...
struct NonAggr5 : Aggr {
};
NonAggr5 na5 = { b };
#if __cplusplus <= 201402L
// expected-error@-2 {{no matching constructor for initialization of 'NonAggr5'}}
// expected-note@-5 3 {{candidate constructor}}
#endif
template<typename...BaseList>
struct MaybeAggr5a : BaseList... {};
MaybeAggr5a<> ma5a0 = {}; // ok
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@-4 {{call to implicitly-deleted default constructor of 'MaybeAggr5a<Aggr>'}}
// expected-note@-7 {{default constructor of 'MaybeAggr5a<Aggr>' is implicitly deleted because base class 'Aggr' has a deleted default constructor}}
// expected-note@13 {{default constructor of 'Aggr' is implicitly deleted because field 'br' of reference type 'bool &' would not be initialized}}
// expected-error@-5 {{no matching constructor}} expected-note@-9 3{{candidate}}
#else
// expected-error@-9 {{reference member of type 'bool &' uninitialized}}
// expected-note@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@-4 {{no matching constructor}} // expected-note@-5 3{{candidate}}
// expected-error@-4 {{no matching constructor}} // expected-note@-6 3{{candidate}}
// expected-error@-4 {{implicitly-deleted default constructor}} expected-note@-7 {{no default constructor}}
#else
// expected-error@-8 {{no viable conversion from 'int' to 'NonAggr1a'}} expected-note@19 2{{candidate}}
// (ok)
// expected-error@-8 {{no matching constructor}} expected-note@19 2{{candidate}} expected-note@20 {{candidate}}
#endif
// 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 } ;

View File

@ -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
}

View File

@ -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@-1 {{in call to 'A({{.*}})'}}
}

View File

@ -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>