diff options
author | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2011-02-26 19:13:13 +0000 |
---|---|---|
committer | Sean Hunt <scshunt@csclub.uwaterloo.ca> | 2011-02-26 19:13:13 +0000 |
commit | 4171766318a2564fbc9a739be0a2851f441c0d29 (patch) | |
tree | 7efce9487dc0c0f09b14f0feba695e2c09ab92dd /lib | |
parent | 448d2cdce2dd8360c09f4187cd7bbebf16ff964d (diff) |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 69 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 7 |
3 files changed, 79 insertions, 9 deletions
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 @@ -1033,6 +1033,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, SourceLocation L, Expr *Init, @@ -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<CXXConstructExpr>(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<Expr>(), + RParenLoc); + } + + return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor, + DelegationInit.takeAs<Expr>(), + 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(); |