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:
parent
a99000dd31
commit
872307e2ac
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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; };
|
||||
|
|
|
@ -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 } ;
|
|
@ -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 } ;
|
|
@ -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
|
||||
}
|
|
@ -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({{.*}})'}}
|
||||
}
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue