diff options
author | John McCall <rjmccall@apple.com> | 2010-07-06 01:34:17 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-07-06 01:34:17 +0000 |
commit | f1549f66a8216a78112286e3978cea2c29d6334c (patch) | |
tree | abcabedb8b72594ef7ea106fc08684927d3a386b /lib/CodeGen/CGClass.cpp | |
parent | 6c47a9b9779216ef24526c064d5b6ab0db0b5009 (diff) |
Validated by nightly-test runs on x86 and x86-64 darwin, including after
self-host. Hopefully these results hold up on different platforms.
I tried to keep the GNU ObjC runtime happy, but it's hard for me to test.
Reimplement how clang generates IR for exceptions. Instead of creating new
invoke destinations which sequentially chain to the previous destination,
push a more semantic representation of *why* we need the cleanup/catch/filter
behavior, then collect that information into a single landing pad upon request.
Also reorganizes how normal cleanups (i.e. cleanups triggered by non-exceptional
control flow) are generated, since it's actually fairly closely tied in with
the former. Remove the need to track which cleanup scope a block is associated
with.
Document a lot of previously poorly-understood (by me, at least) behavior.
The new framework implements the Horrible Hack (tm), which requires every
landing pad to have a catch-all so that inlining will work. Clang no longer
requires the Horrible Hack just to make exceptions flow correctly within
a function, however. The HH is an unfortunate requirement of LLVM's EH IR.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107631 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGClass.cpp')
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 83 |
1 files changed, 49 insertions, 34 deletions
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 085cfd3168..a69a3f9566 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -340,7 +340,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) { // FIXME: Is this OK for C++0x delegating constructors? - CodeGenFunction::EHCleanupBlock Cleanup(CGF); + CodeGenFunction::CleanupBlock Cleanup(CGF, CodeGenFunction::EHCleanup); CXXDestructorDecl *DD = BaseClassDecl->getDestructor(); CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V); @@ -354,7 +354,7 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, QualType T, unsigned Index) { if (Index == MemberInit->getNumArrayIndices()) { - CodeGenFunction::CleanupScope Cleanups(CGF); + CodeGenFunction::RunCleanupsScope Cleanups(CGF); llvm::Value *Dest = LHS.getAddress(); if (ArrayIndexVar) { @@ -410,7 +410,7 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc"); { - CodeGenFunction::CleanupScope Cleanups(CGF); + CodeGenFunction::RunCleanupsScope Cleanups(CGF); // Inside the loop body recurse to emit the inner loop or, eventually, the // constructor call. @@ -534,7 +534,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (!RD->hasTrivialDestructor()) { // FIXME: Is this OK for C++0x delegating constructors? - CodeGenFunction::EHCleanupBlock Cleanup(CGF); + CodeGenFunction::CleanupBlock Cleanup(CGF, CodeGenFunction::EHCleanup); llvm::Value *ThisPtr = CGF.LoadCXXThis(); LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0); @@ -612,7 +612,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { if (IsTryBody) TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body)); - unsigned CleanupStackSize = CleanupEntries.size(); + EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin(); // Emit the constructor prologue, i.e. the base and member // initializers. @@ -628,7 +628,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { // initializers, which includes (along the exceptional path) the // destructors for those members and bases that were fully // constructed. - EmitCleanupBlocks(CleanupStackSize); + PopCleanupBlocks(CleanupDepth); if (IsTryBody) ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo); @@ -648,9 +648,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, B != E; ++B) { CXXBaseOrMemberInitializer *Member = (*B); - assert(LiveTemporaries.empty() && - "Should not have any live temporaries at initializer start!"); - if (Member->isBaseInitializer()) EmitBaseInitializer(*this, ClassDecl, Member, CtorType); else @@ -659,12 +656,8 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, InitializeVTablePointers(ClassDecl); - for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) { - assert(LiveTemporaries.empty() && - "Should not have any live temporaries at initializer start!"); - + for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args); - } } /// EmitDestructorBody - Emits the body of the current destructor. @@ -684,8 +677,28 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { if (isTryBody) TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body)); - llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); - PushCleanupBlock(DtorEpilogue); + // Emit the destructor epilogue now. If this is a complete + // destructor with a function-try-block, perform the base epilogue + // as well. + // + // FIXME: This isn't really right, because an exception in the + // non-EH epilogue should jump to the appropriate place in the + // EH epilogue. + { + CleanupBlock Cleanup(*this, NormalCleanup); + + if (isTryBody && DtorType == Dtor_Complete) + EmitDtorEpilogue(Dtor, Dtor_Base); + EmitDtorEpilogue(Dtor, DtorType); + + if (Exceptions) { + Cleanup.beginEHCleanup(); + + if (isTryBody && DtorType == Dtor_Complete) + EmitDtorEpilogue(Dtor, Dtor_Base); + EmitDtorEpilogue(Dtor, DtorType); + } + } bool SkipBody = false; // should get jump-threaded @@ -724,23 +737,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // 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); + // We're done with the epilogue cleanup. + PopCleanupBlock(); // Exit the try if applicable. if (isTryBody) @@ -939,7 +937,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, // Keep track of the current number of live temporaries. { - CXXTemporariesCleanupScope Scope(*this); + RunCleanupsScope Scope(*this); EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address, ArgBeg, ArgEnd); @@ -1114,6 +1112,23 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0); } +void CodeGenFunction::PushDestructorCleanup(QualType T, llvm::Value *Addr) { + CXXRecordDecl *ClassDecl = T->getAsCXXRecordDecl(); + if (!ClassDecl) return; + if (ClassDecl->hasTrivialDestructor()) return; + + const CXXDestructorDecl *D = ClassDecl->getDestructor(); + + CleanupBlock Scope(*this, NormalCleanup); + + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Addr); + + if (Exceptions) { + Scope.beginEHCleanup(); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Addr); + } +} + llvm::Value * CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, const CXXRecordDecl *ClassDecl, |