summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-10-16 23:30:16 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-10-16 23:30:16 +0000
commit708f69bcc1be715efd1e9f46266a9c1ead184be6 (patch)
tree13bcacac0f1768f91e34404acf57484db5fbb750
parent2eb9a959d24ad757a82ecab61f343635ad67749a (diff)
downloadclang-708f69bcc1be715efd1e9f46266a9c1ead184be6.tar.gz
DR1492: In a definition of a destructor, the exception specification must be
explicitly specified iff it was specified in the declaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166071 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp44
-rw-r--r--test/CXX/special/class.dtor/p3-0x.cpp2
-rw-r--r--test/CXX/special/class.dtor/p3.cpp17
3 files changed, 46 insertions, 17 deletions
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index e0e0d20310..e35badc9f3 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -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);
}
diff --git a/test/CXX/special/class.dtor/p3-0x.cpp b/test/CXX/special/class.dtor/p3-0x.cpp
index 44bf5aa019..291353a823 100644
--- a/test/CXX/special/class.dtor/p3-0x.cpp
+++ b/test/CXX/special/class.dtor/p3-0x.cpp
@@ -45,7 +45,7 @@ G::~G() {}
struct H {
B b;
- ~H();
+ ~H() throw(int);
};
H::~H() throw(int) {}
diff --git a/test/CXX/special/class.dtor/p3.cpp b/test/CXX/special/class.dtor/p3.cpp
new file mode 100644
index 0000000000..c3a292d50c
--- /dev/null
+++ b/test/CXX/special/class.dtor/p3.cpp
@@ -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}}
+}