Fully implement delegating constructors!
As far as I know, this implementation is complete but might be missing a
few optimizations. Exceptions and virtual bases are handled correctly.
Because I'm an optimist, the web page has appropriately been updated. If
I'm wrong, feel free to downgrade its support categories.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130642 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 2cb5549..1227b4c 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -658,6 +658,10 @@
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::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 @@
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 @@
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 2f3e468..e66afc6 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -404,9 +404,16 @@
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 913b5df..169c576 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1496,6 +1496,12 @@
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 bacd624..d6e0d3a 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -561,6 +561,7 @@
.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 bd4aac8..dc0a41e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2068,6 +2068,30 @@
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 @@
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 938ace8..ca3fd6d 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2045,7 +2045,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 =