diff options
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 87 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 54 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/virtual-base-destructor-call.cpp | 34 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/virtual-destructor-calls.cpp | 10 |
4 files changed, 131 insertions, 54 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 863b09c86a9..7b8e736900e 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -477,12 +477,21 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent(); const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent(); - + llvm::Value *VTT; - uint64_t SubVTTIndex = - CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base); - assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); + uint64_t SubVTTIndex; + + // If the record matches the base, this is the complete ctor/dtor + // variant calling the base variant in a class with virtual bases. + if (RD == Base) { + assert(!CGVtableInfo::needsVTTParameter(CGF.CurGD) && + "doing no-op VTT offset in base dtor/ctor?"); + SubVTTIndex = 0; + } else { + SubVTTIndex = CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base); + assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); + } if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) { // A VTT parameter was passed to the constructor, use it. @@ -962,7 +971,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, /// 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. -/// FIXME: This needs to take a CXXDtorType. void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, CXXDtorType DtorType) { assert(!DD->isTrivial() && @@ -970,6 +978,44 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, const CXXRecordDecl *ClassDecl = DD->getParent(); + // In a deleting destructor, we've already called the complete + // destructor as a subroutine, so we just have to delete the + // appropriate value. + if (DtorType == Dtor_Deleting) { + assert(DD->getOperatorDelete() && + "operator delete missing - EmitDtorEpilogue"); + EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), + getContext().getTagDeclType(ClassDecl)); + return; + } + + // For complete destructors, we've already called the base + // destructor (in GenerateBody), so we just need to destruct all the + // virtual bases. + if (DtorType == Dtor_Complete) { + // Handle virtual bases. + for (CXXRecordDecl::reverse_base_class_const_iterator I = + ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); + I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + + // Ignore trivial destructors. + if (BaseClassDecl->hasTrivialDestructor()) + continue; + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), + true, + ClassDecl, + BaseClassDecl); + EmitCXXDestructorCall(D, Dtor_Base, V); + } + return; + } + + assert(DtorType == Dtor_Base); + // Collect the fields. llvm::SmallVector<const FieldDecl *, 16> FieldDecls; for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), @@ -1042,37 +1088,6 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, /*NullCheckValue=*/false); EmitCXXDestructorCall(D, Dtor_Base, V); } - - // If we're emitting a base destructor, we don't want to emit calls to the - // virtual bases. - if (DtorType == Dtor_Base) - return; - - // Handle virtual bases. - for (CXXRecordDecl::reverse_base_class_const_iterator I = - ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - - // Ignore trivial destructors. - if (BaseClassDecl->hasTrivialDestructor()) - continue; - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), - true, - ClassDecl, - BaseClassDecl); - EmitCXXDestructorCall(D, Dtor_Base, V); - } - - // If we have a deleting destructor, emit a call to the delete operator. - if (DtorType == Dtor_Deleting) { - assert(DD->getOperatorDelete() && - "operator delete missing - EmitDtorEpilogue"); - EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), - getContext().getTagDeclType(ClassDecl)); - } } /// EmitCXXAggrConstructorCall - This routine essentially creates a (nested) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ddf4e6431d0..98113a700ec 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -248,39 +248,69 @@ void CodeGenFunction::GenerateBody(GlobalDecl GD, llvm::Function *Fn, 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. - llvm::BasicBlock *DtorEpilogue = 0; 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)) { - DtorEpilogue = createBasicBlock("dtor.epilogue"); + // 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); - InitializeVtablePtrs(DD->getParent()); + // 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 (!Body) + if (SkipBody) { + // skipped + } else if (!Body) { SynthesizeImplicitFunctionBody(GD, Fn, Args); - else { + } else { if (isa<CXXTryStmt>(Body)) OuterTryBlock = cast<CXXTryStmt>(Body); - EmitStmt(Body); } - // Emit special ctor/ctor epilogues. + // Emit special ctor/dtor epilogues. if (isa<CXXConstructorDecl>(FD)) { - // If any of the member initializers are temporaries bound to references - // make sure to emit their destructors. + // 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(); - assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); + EmitBlock(Info.CleanupBlock); - EmitBlock(DtorEpilogue); EmitDtorEpilogue(DD, GD.getDtorType()); - + + // Go ahead and link in the switch and end blocks. if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) diff --git a/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp b/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp index 1ee598afdc3..b6e85e208b1 100644 --- a/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp +++ b/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -16,4 +16,36 @@ basic_iostream<char> res; int main() { } -// CHECK: call void @_ZN9basic_iosD2Ev +// basic_iostream's complete dtor calls its base dtor, then its +// virtual base's dtor. +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED1Ev +// CHECK: call void @_ZN14basic_iostreamIcED2Ev +// CHECK: call void @_ZN9basic_iosD2Ev + +// basic_iostream's deleting dtor calls its complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev +// CHECK: call void @_ZN14basic_iostreamIcED1Ev +// CHECK: call void @_ZdlPv + +// basic_istream's complete dtor calls the base dtor, +// then its virtual base's base dtor. +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED1Ev +// CHECK: call void @_ZN13basic_istreamIcED2Ev +// CHECK: call void @_ZN9basic_iosD2Ev + +// basic_istream's deleting dtor calls the complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev +// CHECK: call void @_ZN13basic_istreamIcED1Ev +// CHECK: call void @_ZdlPv + +// basic_iostream's base dtor calls its non-virtual base dtor. +// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev +// CHECK: call void @_ZN13basic_istreamIcED2Ev +// CHECK: } + +// basic_istream's base dtor is a no-op. +// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev +// CHECK-NOT: call +// CHECK: } diff --git a/clang/test/CodeGenCXX/virtual-destructor-calls.cpp b/clang/test/CodeGenCXX/virtual-destructor-calls.cpp index 650fd69bbe7..8fe10476d4a 100644 --- a/clang/test/CodeGenCXX/virtual-destructor-calls.cpp +++ b/clang/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -8,15 +8,15 @@ struct B : A { virtual ~B(); }; -// Complete dtor. +// Complete dtor: just an alias because there are no virtual bases. // CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev -// Deleting dtor. +// Deleting dtor: defers to the complete dtor. // CHECK: define void @_ZN1BD0Ev -// CHECK: call void @_ZN1AD2Ev -// check: call void @_ZdlPv +// CHECK: call void @_ZN1BD1Ev +// CHECK: call void @_ZdlPv -// Base dtor. +// Base dtor: actually calls A's base dtor. // CHECK: define void @_ZN1BD2Ev // CHECK: call void @_ZN1AD2Ev |