From 1ee635278813d0ca976d2f17688c92f8b1470851 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 16 Oct 2012 23:30:16 +0000 Subject: [PATCH] DR1492: In a definition of a destructor, the exception specification must be explicitly specified iff it was specified in the declaration. llvm-svn: 166071 --- clang/lib/Sema/SemaExceptionSpec.cpp | 44 +++++++++++++-------- clang/test/CXX/special/class.dtor/p3-0x.cpp | 2 +- clang/test/CXX/special/class.dtor/p3.cpp | 17 ++++++++ 3 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 clang/test/CXX/special/class.dtor/p3.cpp diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index e0e0d2031059..e35badc9f3e6 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -120,6 +120,23 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { return SourceDecl->getType()->castAs(); } +/// Get the type that a function had prior to adjustment of the exception +/// specification. +static const FunctionProtoType *getUnadjustedFunctionType(FunctionDecl *Decl) { + if (isa(Decl) && Decl->getTypeSourceInfo()) { + const FunctionProtoType *Ty = + Decl->getTypeSourceInfo()->getType()->getAs(); + 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(); +} + 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(), - Old->getLocation(), - New->getType()->getAs(), - 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(); + 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(); + 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/clang/test/CXX/special/class.dtor/p3-0x.cpp b/clang/test/CXX/special/class.dtor/p3-0x.cpp index 44bf5aa01978..291353a8237e 100644 --- a/clang/test/CXX/special/class.dtor/p3-0x.cpp +++ b/clang/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/clang/test/CXX/special/class.dtor/p3.cpp b/clang/test/CXX/special/class.dtor/p3.cpp new file mode 100644 index 000000000000..c3a292d50c21 --- /dev/null +++ b/clang/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 struct C { + T t; + ~C(); // expected-note {{here}} + }; + template C::~C() noexcept {} // expected-error {{does not match previous}} +}