forked from OSchip/llvm-project
Implement implicit exception specifications of destructors.
llvm-svn: 131528
This commit is contained in:
parent
8c0ee21517
commit
b900f04ccc
|
@ -2644,6 +2644,13 @@ public:
|
|||
void DefineImplicitDestructor(SourceLocation CurrentLocation,
|
||||
CXXDestructorDecl *Destructor);
|
||||
|
||||
/// \brief Build an exception spec for destructors that don't have one.
|
||||
///
|
||||
/// C++11 says that user-defined destructors with no exception spec get one
|
||||
/// that looks as if the destructor was implicitly declared.
|
||||
void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
|
||||
CXXDestructorDecl *Destructor);
|
||||
|
||||
/// \brief Declare all inherited constructors for the given class.
|
||||
///
|
||||
/// \param ClassDecl The class declaration into which the inherited
|
||||
|
|
|
@ -4143,14 +4143,25 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
// This is a C++ destructor declaration.
|
||||
if (DC->isRecord()) {
|
||||
R = CheckDestructorDeclarator(D, R, SC);
|
||||
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
|
||||
|
||||
NewFD = CXXDestructorDecl::Create(Context,
|
||||
cast<CXXRecordDecl>(DC),
|
||||
CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record,
|
||||
D.getSourceRange().getBegin(),
|
||||
NameInfo, R, TInfo,
|
||||
isInline,
|
||||
/*isImplicitlyDeclared=*/false);
|
||||
NewFD = NewDD;
|
||||
isVirtualOkay = true;
|
||||
|
||||
// If the class is complete, then we now create the implicit exception
|
||||
// specification. If the class is incomplete or dependent, we can't do
|
||||
// it yet.
|
||||
if (getLangOptions().CPlusPlus0x && !Record->isDependentType() &&
|
||||
Record->getDefinition() && !Record->isBeingDefined() &&
|
||||
R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
|
||||
AdjustDestructorExceptionSpec(Record, NewDD);
|
||||
}
|
||||
|
||||
} else {
|
||||
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
|
||||
|
||||
|
@ -8128,6 +8139,11 @@ void Sema::ActOnFields(Scope* S,
|
|||
Convs->setAccess(I, (*I)->getAccess());
|
||||
|
||||
if (!CXXRecord->isDependentType()) {
|
||||
// Adjust user-defined destructor exception spec.
|
||||
if (getLangOptions().CPlusPlus0x &&
|
||||
CXXRecord->hasUserDeclaredDestructor())
|
||||
AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor());
|
||||
|
||||
// Add any implicitly-declared members to this class.
|
||||
AddImplicitlyDeclaredMembersToClass(CXXRecord);
|
||||
|
||||
|
|
|
@ -6222,18 +6222,18 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
|
||||
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
|
||||
ExceptSpec.CalledDecl(
|
||||
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
|
||||
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
|
||||
}
|
||||
|
||||
|
||||
// Virtual base-class destructors.
|
||||
for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
|
||||
BEnd = ClassDecl->vbases_end();
|
||||
B != BEnd; ++B) {
|
||||
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
|
||||
ExceptSpec.CalledDecl(
|
||||
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
|
||||
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
|
||||
}
|
||||
|
||||
|
||||
// Field destructors.
|
||||
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
|
||||
FEnd = ClassDecl->field_end();
|
||||
|
@ -6241,7 +6241,7 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
|||
if (const RecordType *RecordTy
|
||||
= Context.getBaseElementType(F->getType())->getAs<RecordType>())
|
||||
ExceptSpec.CalledDecl(
|
||||
LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
|
||||
LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
|
||||
}
|
||||
|
||||
return ExceptSpec;
|
||||
|
@ -6254,7 +6254,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
|
|||
// inline public member of its class.
|
||||
|
||||
ImplicitExceptionSpecification Spec =
|
||||
ComputeDefaultedDtorExceptionSpec(ClassDecl);
|
||||
ComputeDefaultedDtorExceptionSpec(ClassDecl);
|
||||
FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
|
||||
|
||||
// Create the actual destructor declaration.
|
||||
|
@ -6329,6 +6329,35 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
|
|||
}
|
||||
}
|
||||
|
||||
void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
|
||||
CXXDestructorDecl *destructor) {
|
||||
// C++11 [class.dtor]p3:
|
||||
// A declaration of a destructor that does not have an exception-
|
||||
// specification is implicitly considered to have the same exception-
|
||||
// specification as an implicit declaration.
|
||||
const FunctionProtoType *dtorType = destructor->getType()->
|
||||
getAs<FunctionProtoType>();
|
||||
if (dtorType->hasExceptionSpec())
|
||||
return;
|
||||
|
||||
ImplicitExceptionSpecification exceptSpec =
|
||||
ComputeDefaultedDtorExceptionSpec(classDecl);
|
||||
|
||||
// Replace the destructor's type.
|
||||
FunctionProtoType::ExtProtoInfo epi;
|
||||
epi.ExceptionSpecType = exceptSpec.getExceptionSpecType();
|
||||
epi.NumExceptions = exceptSpec.size();
|
||||
epi.Exceptions = exceptSpec.data();
|
||||
QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi);
|
||||
|
||||
destructor->setType(ty);
|
||||
|
||||
// FIXME: If the destructor has a body that could throw, and the newly created
|
||||
// spec doesn't allow exceptions, we should emit a warning, because this
|
||||
// change in behavior can break conforming C++03 programs at runtime.
|
||||
// However, we don't have a body yet, so it needs to be done somewhere else.
|
||||
}
|
||||
|
||||
/// \brief Builds a statement that copies the given entity from \p From to
|
||||
/// \c To.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
struct A {
|
||||
~A();
|
||||
};
|
||||
|
||||
struct B {
|
||||
~B() throw(int);
|
||||
};
|
||||
|
||||
struct C {
|
||||
B b;
|
||||
~C() {}
|
||||
};
|
||||
|
||||
struct D {
|
||||
~D() noexcept(false);
|
||||
};
|
||||
|
||||
struct E {
|
||||
D d;
|
||||
~E() {}
|
||||
};
|
||||
|
||||
void foo() {
|
||||
A a;
|
||||
C c;
|
||||
E e;
|
||||
// CHECK: invoke void @_ZN1ED1Ev
|
||||
// CHECK: invoke void @_ZN1CD1Ev
|
||||
// CHECK: call void @_ZN1AD1Ev
|
||||
}
|
||||
|
||||
struct F {
|
||||
D d;
|
||||
~F();
|
||||
};
|
||||
F::~F() noexcept(false) {}
|
||||
|
||||
struct G {
|
||||
D d;
|
||||
~G();
|
||||
};
|
||||
G::~G() {}
|
||||
|
||||
struct H {
|
||||
B b;
|
||||
~H();
|
||||
};
|
||||
H::~H() throw(int) {}
|
||||
|
||||
struct I {
|
||||
B b;
|
||||
~I();
|
||||
};
|
||||
I::~I() {}
|
||||
|
||||
// Template variants.
|
||||
|
||||
template <typename T>
|
||||
struct TA {
|
||||
~TA();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TB {
|
||||
~TB() throw(int);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TC {
|
||||
TB<T> b;
|
||||
~TC() {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TD {
|
||||
~TD() noexcept(false);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TE {
|
||||
TD<T> d;
|
||||
~TE() {}
|
||||
};
|
||||
|
||||
void tfoo() {
|
||||
TA<int> a;
|
||||
TC<int> c;
|
||||
TE<int> e;
|
||||
// CHECK: invoke void @_ZN2TEIiED1Ev
|
||||
// CHECK: invoke void @_ZN2TCIiED1Ev
|
||||
// CHECK: call void @_ZN2TAIiED1Ev
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct TF {
|
||||
TD<T> d;
|
||||
~TF();
|
||||
};
|
||||
template <typename T>
|
||||
TF<T>::~TF() noexcept(false) {}
|
||||
|
||||
template <typename T>
|
||||
struct TG {
|
||||
TD<T> d;
|
||||
~TG();
|
||||
};
|
||||
template <typename T>
|
||||
TG<T>::~TG() {}
|
||||
|
||||
template <typename T>
|
||||
struct TH {
|
||||
TB<T> b;
|
||||
~TH();
|
||||
};
|
||||
template <typename T>
|
||||
TH<T>::~TH() {}
|
||||
|
||||
void tinst() {
|
||||
TF<int> f;
|
||||
TG<int> g;
|
||||
TH<int> h;
|
||||
}
|
||||
// CHECK: define linkonce_odr void @_ZN2THIiED1Ev
|
||||
// CHECK: _ZTIi
|
||||
// CHECK: __cxa_call_unexpected
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
struct non_trivial {
|
||||
non_trivial();
|
||||
~non_trivial();
|
||||
~non_trivial() noexcept(false);
|
||||
};
|
||||
non_trivial::non_trivial() {}
|
||||
non_trivial::~non_trivial() {}
|
||||
non_trivial::~non_trivial() noexcept(false) {}
|
||||
|
||||
// We use a virtual base to ensure that the constructor
|
||||
// delegation optimization (complete->base) can't be
|
||||
|
|
|
@ -159,7 +159,7 @@ namespace test8 {
|
|||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_(
|
||||
// CHECK: call i8* @__cxa_begin_catch
|
||||
// CHECK-NEXT: invoke void @_ZN5test81AD1Ev(
|
||||
// CHECK-NEXT: call void @_ZN5test81AD1Ev(
|
||||
// CHECK: call void @__cxa_end_catch()
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ namespace test11 {
|
|||
|
||||
// PR7686
|
||||
namespace test12 {
|
||||
struct A { ~A(); };
|
||||
struct A { ~A() noexcept(false); };
|
||||
bool opaque(const A&);
|
||||
|
||||
// CHECK: define void @_ZN6test124testEv()
|
||||
|
@ -392,8 +392,8 @@ namespace test15 {
|
|||
}
|
||||
|
||||
namespace test16 {
|
||||
struct A { A(); ~A(); };
|
||||
struct B { int x; B(const A &); ~B(); };
|
||||
struct A { A(); ~A() noexcept(false); };
|
||||
struct B { int x; B(const A &); ~B() noexcept(false); };
|
||||
void foo();
|
||||
bool cond();
|
||||
|
||||
|
|
Loading…
Reference in New Issue