summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-03-08 22:17:41 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-03-08 22:17:41 +0000
commit872307e2ac6f9a1e8a83e23a5dc0db88538fa860 (patch)
treeab727fb967e4d216dc5456c84842a0850eb21f1a /clang/lib
parenta99000dd311b972e35f889c61bbdbc22a1680abd (diff)
downloadbcm5719-llvm-872307e2ac6f9a1e8a83e23a5dc0db88538fa860.tar.gz
bcm5719-llvm-872307e2ac6f9a1e8a83e23a5dc0db88538fa860.zip
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
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/DeclCXX.cpp25
-rw-r--r--clang/lib/AST/ExprConstant.cpp27
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp42
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp13
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp16
-rw-r--r--clang/lib/Sema/SemaInit.cpp131
6 files changed, 209 insertions, 45 deletions
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 65bfc49daec..385ac0b83e9 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -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;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 89a21acc842..7cc9512d800 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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.
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 947b3d5b858..53131f7557f 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -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.
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 614b0769231..af370972491 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -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;
}
}
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 2aed3bb06d9..d64c5876ee2 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -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;
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index afa681453df..3edabc64288 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -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; };
OpenPOWER on IntegriCloud