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.
/// 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() &&
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(),
/*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)
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)
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: }
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