зеркало из https://github.com/microsoft/clang.git
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:
Родитель
cc0f9f1a3b
Коммит
b76af9c969
|
@ -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}}
|
||||
{}
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче