summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGClass.cpp87
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp54
2 files changed, 93 insertions, 48 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)
OpenPOWER on IntegriCloud