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.
enum ConstructionKind {
CK_Complete,
CK_NonVirtualBase,
- CK_VirtualBase
+ CK_VirtualBase,
+ CK_Delegating
};
private:
"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<
/// \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,
/// \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.
SourceLocation LParenLoc,
CXXRecordDecl *ClassDecl);
+ bool SetDelegatingInitializer(CXXConstructorDecl *Constructor,
+ CXXCtorInitializer *Initializer);
+
bool SetCtorInitializers(CXXConstructorDecl *Constructor,
CXXCtorInitializer **Initializers,
unsigned NumInitializers, bool AnyErrors);
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;
}
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;
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);
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,
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;
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,
.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)
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,
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;
}
}
case EK_New:
case EK_Temporary:
case EK_Base:
- case EK_Delegation:
+ case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_BlockElement:
case EK_New:
case EK_Temporary:
case EK_Base:
- case EK_Delegation:
+ case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_BlockElement:
case EK_New:
case EK_Temporary:
case EK_Base:
- case EK_Delegation:
+ case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_BlockElement:
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:
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:
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;
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();
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 =
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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}}
+}
<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>