Ensure that destructors are properly inovked when an exception leaves

the body of a delegating constructor call.

This means that the delegating constructor implementation should be
complete and correct, though there are some rough edges (diagnostic
quality with the cycle detection and using a deleted destructor).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130803 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sean Hunt 2011-05-03 23:05:34 +00:00
Родитель cc0f9f1a3b
Коммит b76af9c969
4 изменённых файлов: 69 добавлений и 18 удалений

Просмотреть файл

@ -1270,6 +1270,23 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
ReturnValueSlot(), DelegateArgs, Ctor);
}
namespace {
struct CallDelegatingCtorDtor : EHScopeStack::Cleanup {
const CXXDestructorDecl *Dtor;
llvm::Value *Addr;
CXXDtorType Type;
CallDelegatingCtorDtor(const CXXDestructorDecl *D, llvm::Value *Addr,
CXXDtorType Type)
: Dtor(D), Addr(Addr), Type(Type) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
Addr);
}
};
}
void
CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
const FunctionArgList &Args) {
@ -1280,8 +1297,17 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
}
const CXXRecordDecl *ClassDecl = Ctor->getParent();
if (CGM.getLangOptions().Exceptions && !ClassDecl->hasTrivialDestructor()) {
CXXDtorType Type =
CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base;
EHStack.pushCleanup<CallDelegatingCtorDtor>(EHCleanup,
ClassDecl->getDestructor(),
ThisPtr, Type);
}
}
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,

Просмотреть файл

@ -2095,6 +2095,11 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
Constructor->setCtorInitializers(initializer);
if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor);
DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
}
return false;
}

Просмотреть файл

@ -22,27 +22,35 @@ delegator::delegator() {
throw 0;
}
delegator::delegator(bool)
{}
// CHECK: define void @_ZN9delegatorC1Ec
// CHECK: void @_ZN9delegatorC1Eb
// CHECK: void @__cxa_throw
// CHECK: lpad
// CHECK: void @_ZN9delegatorD1Ev
// CHECK: define void @_ZN9delegatorC2Ec
// CHECK: void @_ZN9delegatorC2Eb
// CHECK: void @__cxa_throw
// CHECK: lpad
// CHECK: invoke void @_ZN9delegatorD2Ev
delegator::delegator(char)
: delegator(true) {
throw 0;
}
// CHECK: define void @_ZN9delegatorC1Ei
// CHECK: call void @_ZN9delegatorC1Ev
// CHECK: void @_ZN9delegatorC1Ev
// CHECK-NOT: lpad
// CHECK: ret
// CHECK-NOT: lpad
// CHECK: define void @_ZN9delegatorC2Ei
// CHECK: call void @_ZN9delegatorC2Ev
// CHECK: void @_ZN9delegatorC2Ev
// CHECK-NOT: lpad
// CHECK: ret
// CHECK-NOT: lpad
delegator::delegator(int)
: delegator()
{}
delegator::delegator(bool)
{}
// CHECK: define void @_ZN9delegatorC2Ec
// CHECK: call void @_ZN9delegatorC2Eb
// CHECK: call void @__cxa_throw
delegator::delegator(char)
: delegator(true) {
throw 0;
}

Просмотреть файл

@ -7,8 +7,9 @@ struct foo {
foo(int, int);
foo(bool);
foo(char);
foo(float*);
foo(float&);
foo(const float*);
foo(const float&);
foo(void*);
};
// Good
@ -25,12 +26,23 @@ foo::foo (bool) : foo(true) { // expected-error{{delegates to itself}}
}
// Good
foo::foo (float* f) : foo(*f) {
foo::foo (const float* f) : foo(*f) {
}
// FIXME: This should error
foo::foo (float &f) : foo(&f) {
foo::foo (const float &f) : foo(&f) {
}
foo::foo (char) : i(3), foo(3) { // expected-error{{must appear alone}}
}
// This should not cause an infinite loop
foo::foo (void*) : foo(4.0f) {
}
struct deleted_dtor {
~deleted_dtor() = delete; // expected-note{{function has been explicitly marked deleted here}}
deleted_dtor();
deleted_dtor(int) : deleted_dtor() // expected-error{{attempt to use a deleted function}}
{}
};