DR1492: In a definition of a destructor, the exception specification must be

explicitly specified iff it was specified in the declaration.

llvm-svn: 166071
This commit is contained in:
Richard Smith 2012-10-16 23:30:16 +00:00
parent cced1566e2
commit 1ee6352788
3 changed files with 46 additions and 17 deletions

View File

@ -120,6 +120,23 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceDecl->getType()->castAs<FunctionProtoType>();
}
/// Get the type that a function had prior to adjustment of the exception
/// specification.
static const FunctionProtoType *getUnadjustedFunctionType(FunctionDecl *Decl) {
if (isa<CXXDestructorDecl>(Decl) && Decl->getTypeSourceInfo()) {
const FunctionProtoType *Ty =
Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
if (!Ty->hasExceptionSpec())
// The type will be adjusted. Use the EST_None exception specification
// from the type as written.
return Ty;
}
// Use whatever type the function now has. The TypeSourceInfo does not contain
// an instantiated exception specification for a function template,
return Decl->getType()->getAs<FunctionProtoType>();
}
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
@ -129,16 +146,14 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
PDiag(diag::note_previous_declaration),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
New->getType()->getAs<FunctionProtoType>(),
New->getLocation(),
&MissingExceptionSpecification,
&MissingEmptyExceptionSpecification,
/*AllowNoexceptAllMatchWithNoSpec=*/true,
IsOperatorNew))
// Check the types as written: they must match before any exception
// specification adjustment is applied.
if (!CheckEquivalentExceptionSpec(
PDiag(DiagID), PDiag(diag::note_previous_declaration),
getUnadjustedFunctionType(Old), Old->getLocation(),
getUnadjustedFunctionType(New), New->getLocation(),
&MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
/*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew))
return false;
// The failure was something other than an empty exception
@ -146,8 +161,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
return true;
const FunctionProtoType *NewProto
= New->getType()->getAs<FunctionProtoType>();
const FunctionProtoType *NewProto = getUnadjustedFunctionType(New);
// The new function declaration is only missing an empty exception
// specification "throw()". If the throw() specification came from a
@ -172,8 +186,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
}
if (MissingExceptionSpecification && NewProto) {
const FunctionProtoType *OldProto
= Old->getType()->getAs<FunctionProtoType>();
const FunctionProtoType *OldProto = getUnadjustedFunctionType(Old);
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
@ -290,8 +303,7 @@ bool Sema::CheckEquivalentExceptionSpec(
unsigned DiagID = diag::err_mismatched_exception_spec;
if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
return CheckEquivalentExceptionSpec(
PDiag(DiagID),
return CheckEquivalentExceptionSpec(PDiag(DiagID),
PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
}

View File

@ -45,7 +45,7 @@ G::~G() {}
struct H {
B b;
~H();
~H() throw(int);
};
H::~H() throw(int) {}

View File

@ -0,0 +1,17 @@
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -verify %s
// The exception specification of a destructor declaration is matched *before*
// the exception specification adjustment occurs.
namespace DR1492 {
struct A { ~A(); }; // expected-note {{here}}
A::~A() noexcept {} // expected-error {{does not match previous declaration}}
struct B { ~B() noexcept; }; // expected-note {{here}}
B::~B() {} // expected-warning {{~B' is missing exception specification 'noexcept'}}
template<typename T> struct C {
T t;
~C(); // expected-note {{here}}
};
template<typename T> C<T>::~C() noexcept {} // expected-error {{does not match previous}}
}