diff options
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 177 | ||||
-rw-r--r-- | lib/CodeGen/CGException.cpp | 68 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 86 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 29 | ||||
-rw-r--r-- | test/CodeGenCXX/destructors.cpp | 49 |
5 files changed, 226 insertions, 183 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. diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index d956c1c3cd..142cb811b0 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -427,6 +427,26 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { } void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { + CXXTryStmtInfo Info = EnterCXXTryStmt(S); + EmitStmt(S.getTryBlock()); + ExitCXXTryStmt(S, Info); +} + +CodeGenFunction::CXXTryStmtInfo +CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S) { + CXXTryStmtInfo Info; + Info.SavedLandingPad = getInvokeDest(); + Info.HandlerBlock = createBasicBlock("try.handler"); + Info.FinallyBlock = createBasicBlock("finally"); + + PushCleanupBlock(Info.FinallyBlock); + setInvokeDest(Info.HandlerBlock); + + return Info; +} + +void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, + CXXTryStmtInfo TryInfo) { // Pointer to the personality function llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -439,54 +459,12 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *llvm_eh_selector = CGM.getIntrinsic(llvm::Intrinsic::eh_selector); - llvm::BasicBlock *PrevLandingPad = getInvokeDest(); - llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); - llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); + llvm::BasicBlock *PrevLandingPad = TryInfo.SavedLandingPad; + llvm::BasicBlock *TryHandler = TryInfo.HandlerBlock; + llvm::BasicBlock *FinallyBlock = TryInfo.FinallyBlock; llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); - // Push an EH context entry, used for handling rethrows. - PushCleanupBlock(FinallyBlock); - - // Emit the statements in the try {} block - setInvokeDest(TryHandler); - - // FIXME: We should not have to do this here. The AST should have the member - // initializers under the CXXTryStmt's TryBlock. - if (OuterTryBlock == &S) { - GlobalDecl GD = CurGD; - const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); - - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { - size_t OldCleanupStackSize = CleanupEntries.size(); - EmitCtorPrologue(CD, CurGD.getCtorType()); - EmitStmt(S.getTryBlock()); - - // If any of the member initializers are temporaries bound to references - // make sure to emit their destructors. - EmitCleanupBlocks(OldCleanupStackSize); - } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { - llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); - PushCleanupBlock(DtorEpilogue); - - InitializeVtablePtrs(DD->getParent()); - EmitStmt(S.getTryBlock()); - - CleanupBlockInfo Info = PopCleanupBlock(); - - assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); - EmitBlock(DtorEpilogue); - EmitDtorEpilogue(DD, GD.getDtorType()); - - if (Info.SwitchBlock) - EmitBlock(Info.SwitchBlock); - if (Info.EndBlock) - EmitBlock(Info.EndBlock); - } else - EmitStmt(S.getTryBlock()); - } else - EmitStmt(S.getTryBlock()); - // Jump to end if there is no exception EmitBranchThroughCleanup(FinallyEnd); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 98113a700e..7337590f57 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -241,80 +241,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } } -void CodeGenFunction::GenerateBody(GlobalDecl GD, llvm::Function *Fn, - FunctionArgList &Args) { - const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); +void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) { + const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl()); Stmt *Body = FD->getBody(); - assert((Body || FD->isImplicit()) && "non-implicit function def has no body"); - - bool SkipBody = false; // should get jump-threaded - - // Emit special ctor/dtor prologues. - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { - // Emit the constructor prologue, i.e. the base and member initializers. - EmitCtorPrologue(CD, GD.getCtorType()); - - // TODO: for complete, non-varargs variants, we can get away with - // just emitting the vbase initializers, then calling the base - // constructor. - - } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { - // In all cases, if there's an exception in the body (or delegate) - // we'll still need to run the epilogue. - llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); - PushCleanupBlock(DtorEpilogue); - - // If this is the deleting variant, invoke the complete variant; - // the epilogue will call the appropriate operator delete(). - if (GD.getDtorType() == Dtor_Deleting) { - EmitCXXDestructorCall(DD, Dtor_Complete, LoadCXXThis()); - SkipBody = true; - - // If this is the complete variant, just invoke the base variant; - // the epilogue will destruct the virtual bases. - } else if (GD.getDtorType() == Dtor_Complete) { - EmitCXXDestructorCall(DD, 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(DD->getParent()); - } - } - - // Emit the body of the function. - if (SkipBody) { - // skipped - } else if (!Body) { - SynthesizeImplicitFunctionBody(GD, Fn, Args); - } else { - if (isa<CXXTryStmt>(Body)) - OuterTryBlock = cast<CXXTryStmt>(Body); + if (Body) EmitStmt(Body); - } - - // Emit special ctor/dtor epilogues. - if (isa<CXXConstructorDecl>(FD)) { - // Be sure to 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(0); - - } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { - // Funnel the previously-pushed cleanup block into the epilogue. - CleanupBlockInfo Info = PopCleanupBlock(); - EmitBlock(Info.CleanupBlock); - - EmitDtorEpilogue(DD, GD.getDtorType()); - - // Go ahead and link in the switch and end blocks. - if (Info.SwitchBlock) - EmitBlock(Info.SwitchBlock); - if (Info.EndBlock) - EmitBlock(Info.EndBlock); + else { + assert(FD->isImplicit() && "non-implicit function def has no body"); + assert(FD->isCopyAssignment() && "implicit function not copy assignment"); + SynthesizeCXXCopyAssignment(Args); } } @@ -328,7 +264,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { FunctionArgList Args; CurGD = GD; - OuterTryBlock = 0; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { if (MD->isInstance()) { // Create the implicit 'this' decl. @@ -368,7 +303,12 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { StartFunction(GD, FD->getResultType(), Fn, Args, BodyRange.getBegin()); // Generate the body of the function. - GenerateBody(GD, Fn, Args); + if (isa<CXXDestructorDecl>(FD)) + EmitDestructorBody(Args); + else if (isa<CXXConstructorDecl>(FD)) + EmitConstructorBody(Args); + else + EmitFunctionBody(Args); // Emit the standard function epilogue. FinishFunction(BodyRange.getEnd()); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 29c75fdb8e..1c5cd67fa9 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -91,9 +91,6 @@ public: /// CurGD - The GlobalDecl for the current function being compiled. GlobalDecl CurGD; - /// OuterTryBlock - This is the address of the outter most try block, 0 - /// otherwise. - const Stmt *OuterTryBlock; /// ReturnBlock - Unified return block. llvm::BasicBlock *ReturnBlock; @@ -494,7 +491,9 @@ public: const FunctionArgList &Args, SourceLocation StartLoc); - void GenerateBody(GlobalDecl GD, llvm::Function *Fn, FunctionArgList &Args); + void EmitConstructorBody(FunctionArgList &Args); + void EmitDestructorBody(FunctionArgList &Args); + void EmitFunctionBody(FunctionArgList &Args); /// EmitReturnBlock - Emit the unified return block, trying to avoid its /// emission when possible. @@ -529,18 +528,8 @@ public: llvm::Value *ThisPtr, uint64_t Offset); - void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args); - - void SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, - llvm::Function *Fn, - const FunctionArgList &Args); - - void SynthesizeImplicitFunctionBody(GlobalDecl GD, - llvm::Function *Fn, - const FunctionArgList &Args); + void SynthesizeCXXCopyConstructor(const FunctionArgList &Args); + void SynthesizeCXXCopyAssignment(const FunctionArgList &Args); /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes in @@ -927,6 +916,14 @@ public: void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S); void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); + struct CXXTryStmtInfo { + llvm::BasicBlock *SavedLandingPad; + llvm::BasicBlock *HandlerBlock; + llvm::BasicBlock *FinallyBlock; + }; + CXXTryStmtInfo EnterCXXTryStmt(const CXXTryStmt &S); + void ExitCXXTryStmt(const CXXTryStmt &S, CXXTryStmtInfo Info); + void EmitCXXTryStmt(const CXXTryStmt &S); //===--------------------------------------------------------------------===// diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index 0a7e1e5505..f06661a744 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - +// RUN: %clang_cc1 %s -emit-llvm -o - -mconstructor-aliases | FileCheck %s struct A { int a; @@ -42,3 +42,50 @@ namespace PR5529 { B::~B() {} } + +// FIXME: there's a known problem in the codegen here where, if one +// destructor throws, the remaining destructors aren't run. Fix it, +// then make this code check for it. +namespace test0 { + void foo(); + struct VBase { ~VBase(); }; + struct Base { ~Base(); }; + struct Member { ~Member(); }; + + struct A : Base { + Member M; + ~A(); + }; + + // The function-try-block won't suppress -mconstructor-aliases here. + A::~A() try { } catch (int i) {} + +// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev + +// CHECK: define void @_ZN5test01AD2Ev +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] + + struct B : Base, virtual VBase { + Member M; + ~B(); + }; + B::~B() try { } catch (int i) {} + // It will suppress the delegation optimization here, though. + +// CHECK: define void @_ZN5test01BD1Ev +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test05VBaseD2Ev +// CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]] + +// CHECK: define void @_ZN5test01BD2Ev +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] +} |