diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-03-08 22:17:41 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-03-08 22:17:41 +0000 |
| commit | 872307e2ac6f9a1e8a83e23a5dc0db88538fa860 (patch) | |
| tree | ab727fb967e4d216dc5456c84842a0850eb21f1a /clang/lib | |
| parent | a99000dd311b972e35f889c61bbdbc22a1680abd (diff) | |
| download | bcm5719-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.cpp | 25 | ||||
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 27 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 42 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 16 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 131 |
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; }; |

