From: Sean Hunt Date: Sat, 26 Feb 2011 19:13:13 +0000 (+0000) Subject: Implement delegating constructors partially. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4171766318a2564fbc9a739be0a2851f441c0d29;p=clang Implement delegating constructors partially. This successfully performs constructor lookup and verifies that a delegating initializer is the only initializer present. This does not perform loop detection in the initialization, but it also doesn't codegen delegating constructors at all, so this won't cause runtime infinite loops yet. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126552 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 1656a7e973..45108c37e0 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1148,13 +1148,16 @@ public: /// @endcode class CXXCtorInitializer { /// \brief Either the base class name (stored as a TypeSourceInfo*), an normal - /// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being - /// initialized. - llvm::PointerUnion3 + /// field (FieldDecl), anonymous field (IndirectFieldDecl*), or target + /// constructor (CXXConstructorDecl*) being initialized. + llvm::PointerUnion4 Initializee; /// \brief The source location for the field name or, for a base initializer - /// pack expansion, the location of the ellipsis. + /// pack expansion, the location of the ellipsis. In the case of a delegating + /// constructor, it will still include the type's source location as the + /// Initializee points to the CXXConstructorDecl (to allow loop detection). SourceLocation MemberOrEllipsisLocation; /// \brief The argument used to initialize the base or member, which may @@ -1199,11 +1202,17 @@ public: SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R); + /// CXXCtorInitializer - Creates a new anonymous field initializer. explicit CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R); + /// CXXCtorInitializer - Creates a new delegating Initializer. + explicit + CXXCtorInitializer(ASTContext &Context, SourceLocation D, SourceLocation L, + CXXConstructorDecl *Target, Expr *Init, SourceLocation R); + /// \brief Creates a new member initializer that optionally contains /// array indices used to describe an elementwise initialization. static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member, @@ -1227,6 +1236,12 @@ public: return Initializee.is(); } + /// isDelegatingInitializer - Returns true when this initializer is creating + /// a delegating constructor. + bool isDelegatingInitializer() const { + return Initializee.is(); + } + /// \brief Determine whether this initializer is a pack expansion. bool isPackExpansion() const { return isBaseInitializer() && MemberOrEllipsisLocation.isValid(); @@ -1284,6 +1299,13 @@ public: return 0; } + CXXConstructorDecl *getTargetConstructor() const { + if (isDelegatingInitializer()) + return Initializee.get(); + else + return 0; + } + SourceLocation getMemberLocation() const { return MemberOrEllipsisLocation; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a9fb2da001..4b3b335519 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -798,8 +798,8 @@ def err_ident_in_pseudo_dtor_not_a_type : Error< def err_init_conversion_failed : Error< "cannot initialize %select{a variable|a parameter|return object|an " "exception object|a member subobject|an array element|a new value|a value|a " - "base class|a vector element}0 of type %1 with an %select{rvalue|lvalue}2 of " - "type %3">; + "base class|a constructor delegation|a vector element}0 of type %1 with an " + "%select{rvalue|lvalue}2 of type %3">; def err_lvalue_to_rvalue_ref : Error<"rvalue reference to type %0 cannot bind " "to lvalue of type %1">; @@ -969,6 +969,8 @@ def err_delegation_0x_only : Error< "delegating constructors are permitted only in C++0x">; def err_delegation_unimplemented : Error< "delegating constructors are not fully implemented">; +def err_delegating_initializer_alone : Error< + "an initializer for a delegating constructor must appear alone">; // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index bdf0d8e7b6..7ccd27201c 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -64,6 +64,8 @@ public: EK_Temporary, /// \brief The entity being initialized is a base member subobject. EK_Base, + /// \brief The initialization is being done by a delegating constructor. + EK_Delegation, /// \brief The entity being initialized is an element of a vector. /// or vector. EK_VectorElement, @@ -210,6 +212,11 @@ public: static InitializedEntity InitializeBase(ASTContext &Context, CXXBaseSpecifier *Base, bool IsInheritedVirtualBase); + + /// \brief Create the initialization entity for a delegated constructor. + static InitializedEntity InitializeDelegation(QualType Type) { + return InitializedEntity(EK_Delegation, SourceLocation(), Type); + } /// \brief Create the initialization entity for a member subobject. static InitializedEntity InitializeMember(FieldDecl *Member, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a93739892c..7a1a9f6b09 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2818,10 +2818,10 @@ public: MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr **Args, unsigned NumArgs, + SourceLocation BaseLoc, SourceLocation RParenLoc, SourceLocation LParenLoc, - CXXRecordDecl *ClassDecl, - SourceLocation EllipsisLoc); + CXXRecordDecl *ClassDecl); bool SetCtorInitializers(CXXConstructorDecl *Constructor, CXXCtorInitializer **Initializers, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 46768c12d8..1b849a58ad 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1032,6 +1032,16 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, { } +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + SourceLocation D, SourceLocation L, + CXXConstructorDecl *Target, Expr *Init, + SourceLocation R) + : Initializee(Target), MemberOrEllipsisLocation(D), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(0) +{ +} + CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, @@ -1076,7 +1086,7 @@ const Type *CXXCtorInitializer::getBaseClass() const { } SourceLocation CXXCtorInitializer::getSourceLocation() const { - if (isAnyMemberInitializer()) + if (isAnyMemberInitializer() || isDelegatingInitializer()) return getMemberLocation(); return getBaseClassLoc().getLocalSourceRange().getBegin(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f483262a8c..457ae85941 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -21,6 +21,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" @@ -1476,17 +1477,61 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, MemInitResult Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr **Args, unsigned NumArgs, + SourceLocation NameLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, - CXXRecordDecl *ClassDecl, - SourceLocation EllipsisLoc) { + CXXRecordDecl *ClassDecl) { SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!LangOpts.CPlusPlus0x) return Diag(Loc, diag::err_delegation_0x_only) << TInfo->getTypeLoc().getLocalSourceRange(); - return Diag(Loc, diag::err_delegation_unimplemented) - << TInfo->getTypeLoc().getLocalSourceRange(); + // Initialize the object. + InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( + QualType(ClassDecl->getTypeForDecl(), 0)); + InitializationKind Kind = + InitializationKind::CreateDirect(NameLoc, LParenLoc, RParenLoc); + + InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); + + ExprResult DelegationInit = + InitSeq.Perform(*this, DelegationEntity, Kind, + MultiExprArg(*this, Args, NumArgs), 0); + if (DelegationInit.isInvalid()) + return true; + + CXXConstructExpr *ConExpr = cast(DelegationInit.get()); + CXXConstructorDecl *Constructor = ConExpr->getConstructor(); + assert(Constructor && "Delegating constructor with no target?"); + + CheckImplicitConversions(DelegationInit.get(), LParenLoc); + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + DelegationInit = MaybeCreateExprWithCleanups(DelegationInit); + if (DelegationInit.isInvalid()) + return true; + + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) { + ExprResult Init + = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, + NumArgs, RParenLoc)); + return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, + Constructor, Init.takeAs(), + RParenLoc); + } + + return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor, + DelegationInit.takeAs(), + RParenLoc); } MemInitResult @@ -1538,9 +1583,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (!Dependent) { if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), BaseType)) - return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, - LParenLoc, RParenLoc, ClassDecl, - EllipsisLoc); + return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, BaseLoc, + LParenLoc, RParenLoc, ClassDecl); FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); @@ -2340,10 +2384,19 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, if (CheckRedundantInit(*this, Init, Members[Field]) || CheckRedundantUnionInit(*this, Init, MemberUnions)) HadError = true; - } else { + } else if (Init->isBaseInitializer()) { void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0)); if (CheckRedundantInit(*this, Init, Members[Key])) HadError = true; + } else { + assert(Init->isDelegatingInitializer()); + // This must be the only initializer + if (i != 0 || NumMemInits > 1) { + Diag(MemInits[0]->getSourceLocation(), + diag::err_delegating_initializer_alone) + << MemInits[0]->getSourceRange(); + HadError = true; + } } } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 5882da0eab..358e5fb501 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1998,6 +1998,7 @@ DeclarationName InitializedEntity::getName() const { case EK_New: case EK_Temporary: case EK_Base: + case EK_Delegation: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -2020,6 +2021,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_New: case EK_Temporary: case EK_Base: + case EK_Delegation: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -2042,6 +2044,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_New: case EK_Temporary: case EK_Base: + case EK_Delegation: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -3289,6 +3292,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_New: case InitializedEntity::EK_Exception: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegation: return Sema::AA_Initializing; case InitializedEntity::EK_Parameter: @@ -3325,6 +3329,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_New: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegation: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: @@ -3346,6 +3351,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Result: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegation: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: return false; @@ -3430,6 +3436,7 @@ static ExprResult CopyObject(Sema &S, case InitializedEntity::EK_Temporary: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegation: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: Loc = CurInitExpr->getLocStart();