aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGClass.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-02-19 09:25:03 +0000
committerJohn McCall <rjmccall@apple.com>2010-02-19 09:25:03 +0000
commit9fc6a7774643a810c8501dae2323e863fefb623e (patch)
tree5e1022305d460e971bfeca65e95cbf15597c9808 /lib/CodeGen/CGClass.cpp
parent8c0b9646f54499ee88a3b3df308a2bfbaafac345 (diff)
More refactoring around constructor/destructor code generation.
Fix some bugs with function-try-blocks and simplify normal try-block code generation. This implementation excludes a deleting destructor's call to operator delete() from the function-try-block, which I believe is correct but which I can't find straightforward support for at a moment's glance. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96670 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGClass.cpp')
-rw-r--r--lib/CodeGen/CGClass.cpp177
1 files changed, 129 insertions, 48 deletions
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 7b8e736900..d30d218687 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -14,6 +14,7 @@
#include "CodeGenFunction.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtCXX.h"
using namespace clang;
using namespace CodeGen;
@@ -599,46 +600,6 @@ void CodeGenFunction::EmitClassCopyAssignment(
Callee, ReturnValueSlot(), CallArgs, MD);
}
-/// Synthesizes an implicit function body. Since these only arise in
-/// C++, we only do them in C++.
-void CodeGenFunction::SynthesizeImplicitFunctionBody(GlobalDecl GD,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
- const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-
- // FIXME: this should become isImplicitlyDefined() once we properly
- // support that for C++0x.
- assert(FD->isImplicit() && "Cannot synthesize a non-implicit function");
-
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
- assert(!CD->isTrivial() && "shouldn't need to synthesize a trivial ctor");
-
- if (CD->isDefaultConstructor()) {
- // Sema generates base and member initializers as for this, so
- // the ctor prologue is good enough here.
- return;
- } else {
- assert(CD->isCopyConstructor());
- return SynthesizeCXXCopyConstructor(CD, GD.getCtorType(), Fn, Args);
- }
- }
-
- if (isa<CXXDestructorDecl>(FD)) {
- // The dtor epilogue does everything we'd need to do here.
- return;
- }
-
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(FD);
-
- // FIXME: in C++0x we might have user-declared copy assignment operators
- // coexisting with implicitly-defined ones.
- assert(MD->isCopyAssignment() &&
- !MD->getParent()->hasUserDeclaredCopyAssignment() &&
- "Cannot synthesize a method that is not an implicitly-defined "
- "copy constructor");
- SynthesizeCXXCopyAssignment(MD, Fn, Args);
-}
-
/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a
/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03
/// The implicitly-defined copy constructor for class X performs a memberwise
@@ -655,10 +616,8 @@ void CodeGenFunction::SynthesizeImplicitFunctionBody(GlobalDecl GD,
/// implicitly-defined copy constructor
void
-CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
- CXXCtorType Type,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
+CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
+ const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
const CXXRecordDecl *ClassDecl = Ctor->getParent();
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
"SynthesizeCXXCopyConstructor - copy constructor has definition already");
@@ -754,10 +713,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
///
/// if the subobject is of scalar type, the built-in assignment operator is
/// used.
-void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
- llvm::Function *Fn,
- const FunctionArgList &Args) {
-
+void CodeGenFunction::SynthesizeCXXCopyAssignment(const FunctionArgList &Args) {
+ const CXXMethodDecl *CD = cast<CXXMethodDecl>(CurGD.getDecl());
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
"SynthesizeCXXCopyAssignment - copy assignment has user declaration");
@@ -934,6 +891,52 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
}
}
+/// EmitConstructorBody - Emits the body of the current constructor.
+void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
+ const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
+ CXXCtorType CtorType = CurGD.getCtorType();
+
+ Stmt *Body = Ctor->getBody();
+
+ // Some of the optimizations we want to do can't be done with
+ // function try blocks.
+ CXXTryStmtInfo TryInfo;
+ bool isTryBody = (Body && isa<CXXTryStmt>(Body));
+ if (isTryBody)
+ TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body));
+
+ unsigned CleanupStackSize = CleanupEntries.size();
+
+ // Emit the constructor prologue, i.e. the base and member initializers.
+
+ // TODO: for non-variadic complete-object constructors without a
+ // function try block for a body, we can get away with just emitting
+ // the vbase initializers, then calling the base constructor.
+ EmitCtorPrologue(Ctor, CtorType);
+
+ // Emit the body of the statement.
+ if (isTryBody)
+ EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
+ else if (Body)
+ EmitStmt(Body);
+ else {
+ assert(Ctor->isImplicit() && "bodyless ctor not implicit");
+ if (!Ctor->isDefaultConstructor()) {
+ assert(Ctor->isCopyConstructor());
+ SynthesizeCXXCopyConstructor(Args);
+ }
+ }
+
+ // Emit any cleanup blocks associated with the member or base
+ // initializers, which includes (along the exceptional path) the
+ // destructors for those members and bases that were fully
+ // constructed.
+ EmitCleanupBlocks(CleanupStackSize);
+
+ if (isTryBody)
+ ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo);
+}
+
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
@@ -968,6 +971,84 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
}
}
+/// EmitDestructorBody - Emits the body of the current destructor.
+void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
+ CXXDtorType DtorType = CurGD.getDtorType();
+
+ Stmt *Body = Dtor->getBody();
+
+ // If the body is a function-try-block, enter the try before
+ // anything else --- unless we're in a deleting destructor, in which
+ // case we're just going to call the complete destructor and then
+ // call operator delete() on the way out.
+ CXXTryStmtInfo TryInfo;
+ bool isTryBody = (DtorType != Dtor_Deleting &&
+ Body && isa<CXXTryStmt>(Body));
+ if (isTryBody)
+ TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body));
+
+ llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
+ PushCleanupBlock(DtorEpilogue);
+
+ bool SkipBody = false; // should get jump-threaded
+
+ // If this is the deleting variant, just invoke the complete
+ // variant, then call the appropriate operator delete() on the way
+ // out.
+ if (DtorType == Dtor_Deleting) {
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, LoadCXXThis());
+ SkipBody = true;
+
+ // If this is the complete variant, just invoke the base variant;
+ // the epilogue will destruct the virtual bases. But we can't do
+ // this optimization if the body is a function-try-block, because
+ // we'd introduce *two* handler blocks.
+ } else if (!isTryBody && DtorType == Dtor_Complete) {
+ EmitCXXDestructorCall(Dtor, Dtor_Base, LoadCXXThis());
+ SkipBody = true;
+
+ // Otherwise, we're in the base variant, so we need to ensure the
+ // vtable ptrs are right before emitting the body.
+ } else {
+ InitializeVtablePtrs(Dtor->getParent());
+ }
+
+ // Emit the body of the statement.
+ if (SkipBody)
+ (void) 0;
+ else if (isTryBody)
+ EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
+ else if (Body)
+ EmitStmt(Body);
+ else {
+ assert(Dtor->isImplicit() && "bodyless dtor not implicit");
+ // nothing to do besides what's in the epilogue
+ }
+
+ // Jump to the cleanup block.
+ CleanupBlockInfo Info = PopCleanupBlock();
+ assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
+ EmitBlock(DtorEpilogue);
+
+ // Emit the destructor epilogue now. If this is a complete
+ // destructor with a function-try-block, perform the base epilogue
+ // as well.
+ if (isTryBody && DtorType == Dtor_Complete)
+ EmitDtorEpilogue(Dtor, Dtor_Base);
+ EmitDtorEpilogue(Dtor, DtorType);
+
+ // Link up the cleanup information.
+ if (Info.SwitchBlock)
+ EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ EmitBlock(Info.EndBlock);
+
+ // Exit the try if applicable.
+ if (isTryBody)
+ ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo);
+}
+
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
/// destructor. This is to call destructors on members and base classes
/// in reverse order of their construction.