diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 17 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Sema/Initialization.h | 4 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 24 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 13 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 6 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 28 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 17 | ||||
-rw-r--r-- | test/CodeGenCXX/cxx0x-delegating-ctors.cpp | 48 | ||||
-rw-r--r-- | test/SemaCXX/cxx0x-delegating-ctors.cpp | 36 | ||||
-rw-r--r-- | www/cxx_status.html | 8 |
14 files changed, 194 insertions, 18 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 9d337382a5..8c819e3878 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1608,6 +1608,23 @@ public: void setCtorInitializers(CXXCtorInitializer ** initializers) { CtorInitializers = initializers; } + + /// isDelegatingConstructor - Whether this constructor is a + /// delegating constructor + bool isDelegatingConstructor() const { + return (getNumCtorInitializers() == 1) && + CtorInitializers[0]->isDelegatingInitializer(); + } + + /// getTargetConstructor - When this constructor delegates to + /// another, retrieve the target + CXXConstructorDecl *getTargetConstructor() const { + if (isDelegatingConstructor()) + return CtorInitializers[0]->getTargetConstructor(); + else + return 0; + } + /// isDefaultConstructor - Whether this constructor is a default /// constructor (C++ [class.ctor]p5), which can be used to /// default-initialize a class of this type. diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 0040f13cd3..a970579737 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -780,7 +780,8 @@ public: enum ConstructionKind { CK_Complete, CK_NonVirtualBase, - CK_VirtualBase + CK_VirtualBase, + CK_Delegating }; private: diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 04ff97c155..b05e13313e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1008,6 +1008,10 @@ 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">; +def err_delegating_ctor_loop : Error< + "constructor %0 delegates to itself (possibly indirectly)">; +def err_delegating_codegen_not_implemented : Error< + "code generation for delegating constructors not implemented">; // C++0x range-based for loop def err_for_range_decl_must_be_var : Error< diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index d3865ce314..e83e5c0ccf 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -65,7 +65,7 @@ public: /// \brief The entity being initialized is a base member subobject. EK_Base, /// \brief The initialization is being done by a delegating constructor. - EK_Delegation, + EK_Delegating, /// \brief The entity being initialized is an element of a vector. /// or vector. EK_VectorElement, @@ -215,7 +215,7 @@ public: /// \brief Create the initialization entity for a delegated constructor. static InitializedEntity InitializeDelegation(QualType Type) { - return InitializedEntity(EK_Delegation, SourceLocation(), Type); + return InitializedEntity(EK_Delegating, SourceLocation(), Type); } /// \brief Create the initialization entity for a member subobject. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0744ced9e9..7dc42b9c56 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3072,6 +3072,9 @@ public: SourceLocation LParenLoc, CXXRecordDecl *ClassDecl); + bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, + CXXCtorInitializer *Initializer); + bool SetCtorInitializers(CXXConstructorDecl *Constructor, CXXCtorInitializer **Initializers, unsigned NumInitializers, bool AnyErrors); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 2cb554902e..1227b4c1b2 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -658,6 +658,10 @@ static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) { if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic()) return false; + // FIXME: Decide if we can do a delegation of a delegating constructor. + if (Ctor->isDelegatingConstructor()) + return false; + return true; } @@ -710,6 +714,9 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType CtorType, FunctionArgList &Args) { + if (CD->isDelegatingConstructor()) + return EmitDelegatingCXXConstructorCall(CD, Args); + const CXXRecordDecl *ClassDecl = CD->getParent(); llvm::SmallVector<CXXCtorInitializer *, 8> MemberInitializers; @@ -721,8 +728,10 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, if (Member->isBaseInitializer()) EmitBaseInitializer(*this, ClassDecl, Member, CtorType); - else + else if (Member->isAnyMemberInitializer()) MemberInitializers.push_back(Member); + else + llvm_unreachable("Delegating initializer on non-delegating constructor"); } InitializeVTablePointers(ClassDecl); @@ -1262,6 +1271,19 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, ReturnValueSlot(), DelegateArgs, Ctor); } +void +CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, + const FunctionArgList &Args) { + assert(Ctor->isDelegatingConstructor()); + + llvm::Value *ThisPtr = LoadCXXThis(); + + AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true); + + EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot); +} + + void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, bool ForVirtualBase, diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 2f3e4680a7..e66afc6290 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -404,9 +404,16 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, E->arg_begin(), E->arg_end()); } else { - CXXCtorType Type = - (E->getConstructionKind() == CXXConstructExpr::CK_Complete) - ? Ctor_Complete : Ctor_Base; + CXXCtorType Type; + CXXConstructExpr::ConstructionKind K = E->getConstructionKind(); + if (K == CXXConstructExpr::CK_Delegating) { + // We should be emitting a constructor; GlobalDecl will assert this + Type = CurGD.getCtorType(); + } else { + Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete) + ? Ctor_Complete : Ctor_Base; + } + bool ForVirtualBase = E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 913b5dfa7d..169c576f1a 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1496,6 +1496,12 @@ public: void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args); + // It's important not to confuse this and the previous function. Delegating + // constructors are the C++0x feature. The constructor delegate optimization + // is used to reduce duplication in the base and complete consturctors where + // they are substantially the same. + void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, + const FunctionArgList &Args); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index bacd62464a..d6e0d3a1c0 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -561,6 +561,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_auto_type", LangOpts.CPlusPlus0x) .Case("cxx_decltype", LangOpts.CPlusPlus0x) .Case("cxx_default_function_template_args", LangOpts.CPlusPlus0x) + .Case("cxx_delegating_constructors", LangOpts.CPlusPlus0x) .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x) .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x) //.Case("cxx_lambdas", false) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index bd4aac8985..dc0a41e79e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2068,6 +2068,30 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, return false; } + +bool +Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, + CXXCtorInitializer *Initializer) { + Constructor->setNumCtorInitializers(1); + CXXCtorInitializer **initializer = + new (Context) CXXCtorInitializer*[1]; + memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*)); + Constructor->setCtorInitializers(initializer); + + // FIXME: This doesn't catch indirect loops yet + CXXConstructorDecl *Target = Initializer->getTargetConstructor(); + while (Target) { + if (Target == Constructor) { + Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop) + << Constructor; + return true; + } + Target = Target->getTargetConstructor(); + } + + return false; +} + bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, @@ -2442,7 +2466,11 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, diag::err_delegating_initializer_alone) << MemInits[0]->getSourceRange(); HadError = true; + // We will treat this as being the only initializer. } + SetDelegatingInitializer(Constructor, *MemInits); + // Return immediately as the initializer is set. + return; } } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 938ace851e..ca3fd6dfcb 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2045,7 +2045,7 @@ DeclarationName InitializedEntity::getName() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_Delegation: + case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -2068,7 +2068,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_Delegation: + case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -2091,7 +2091,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_Delegation: + case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -3346,7 +3346,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_New: case InitializedEntity::EK_Exception: case InitializedEntity::EK_Base: - case InitializedEntity::EK_Delegation: + case InitializedEntity::EK_Delegating: return Sema::AA_Initializing; case InitializedEntity::EK_Parameter: @@ -3383,7 +3383,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_Delegating: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: @@ -3405,7 +3405,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_Delegating: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: return false; @@ -3490,7 +3490,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_Delegating: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: Loc = CurInitExpr->getLocStart(); @@ -4061,6 +4061,9 @@ InitializationSequence::Perform(Sema &S, CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; } + if (Entity.getKind() == InitializedEntity::EK_Delegating) { + ConstructKind = CXXConstructExpr::CK_Delegating; + } // Only get the parenthesis range if it is a direct construction. SourceRange parenRange = diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp new file mode 100644 index 0000000000..5b432c7690 --- /dev/null +++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -emit-llvm -fexceptions -fcxx-exceptions -std=c++0x -o - %s | FileCheck %s + +struct non_trivial { + non_trivial(); + ~non_trivial(); +}; +non_trivial::non_trivial() {} +non_trivial::~non_trivial() {} + +// We use a virtual base to ensure that the constructor +// delegation optimization (complete->base) can't be +// performed. +struct delegator { + non_trivial n; + delegator(); + delegator(int); + delegator(char); + delegator(bool); +}; + +delegator::delegator() { + throw 0; +} + +// CHECK: define void @_ZN9delegatorC1Ei +// CHECK: call void @_ZN9delegatorC1Ev +// CHECK-NOT: lpad +// CHECK: ret +// CHECK-NOT: lpad +// CHECK: define void @_ZN9delegatorC2Ei +// CHECK: call void @_ZN9delegatorC2Ev +// CHECK-NOT: lpad +// CHECK: ret +// CHECK-NOT: lpad +delegator::delegator(int) + : delegator() +{} + +delegator::delegator(bool) +{} + +// CHECK: define void @_ZN9delegatorC2Ec +// CHECK: call void @_ZN9delegatorC2Eb +// CHECK: call void @__cxa_throw +delegator::delegator(char) + : delegator(true) { + throw 0; +} diff --git a/test/SemaCXX/cxx0x-delegating-ctors.cpp b/test/SemaCXX/cxx0x-delegating-ctors.cpp new file mode 100644 index 0000000000..b211cb1fe0 --- /dev/null +++ b/test/SemaCXX/cxx0x-delegating-ctors.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s + +struct foo { + int i; + foo(); + foo(int); + foo(int, int); + foo(bool); + foo(char); + foo(float*); + foo(float&); +}; + +// Good +foo::foo (int i) : i(i) { +} +// Good +foo::foo () : foo(-1) { +} +// Good +foo::foo (int, int) : foo() { +} + +foo::foo (bool) : foo(true) { // expected-error{{delegates to itself}} +} + +// Good +foo::foo (float* f) : foo(*f) { +} + +// FIXME: This should error +foo::foo (float &f) : foo(&f) { +} + +foo::foo (char) : i(3), foo(3) { // expected-error{{must appear alone}} +} diff --git a/www/cxx_status.html b/www/cxx_status.html index 40c623fd9a..f0361d38a5 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -348,10 +348,10 @@ welcome!</p> <tr><td colspan="7" class="category">Class Modifications</td></tr> <tr> <td>delegating constructors</td> - <td></td> - <td></td> - <td></td> - <td></td> + <td class="complete"></td> + <td class="complete"></td> + <td class="complete"></td> + <td class="complete"></td> <td>12.6.2</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986">N1986</a></td> </tr> |