mirror of https://github.com/microsoft/clang.git
[c++1z] P0003R5: Removing dynamic exception specifications.
We continue to support dynamic exception specifications in C++1z as an extension, but produce an error-by-default warning when we encounter one. This allows users to opt back into the feature with a warning flag, and implicitly opts system headers back into the feature should they happen to use it. There is one semantic change implied by P0003R5 but not implemented here: violating a throw() exception specification should now call std::terminate directly instead of calling std::unexpected(), but since P0003R5 also removes std::unexpected() and std::set_unexpected, and the default unexpected handler calls std::terminate(), a conforming C++1z program cannot tell that we are still calling it. The upside of this strategy is perfect backwards compatibility; the downside is that we don't get the more efficient 'noexcept' codegen for 'throw()'. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289019 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f5457ae5eb
commit
1f0155f243
|
@ -97,6 +97,8 @@ def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
|
|||
def UnguardedAvailability : DiagGroup<"unguarded-availability">;
|
||||
// partial-availability is an alias of unguarded-availability.
|
||||
def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
|
||||
def DeprecatedDynamicExceptionSpec
|
||||
: DiagGroup<"deprecated-dynamic-exception-spec">;
|
||||
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
|
||||
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
|
||||
def DeprecatedRegister : DiagGroup<"deprecated-register">;
|
||||
|
@ -105,11 +107,15 @@ def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
|
|||
// FIXME: Why is DeprecatedImplementations not in this group?
|
||||
def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes,
|
||||
DeprecatedDeclarations,
|
||||
DeprecatedDynamicExceptionSpec,
|
||||
DeprecatedIncrementBool,
|
||||
DeprecatedRegister,
|
||||
DeprecatedWritableStr]>,
|
||||
DiagCategory<"Deprecations">;
|
||||
|
||||
def DynamicExceptionSpec
|
||||
: DiagGroup<"dynamic-exception-spec", [DeprecatedDynamicExceptionSpec]>;
|
||||
|
||||
def LibLTO : DiagGroup<"liblto">;
|
||||
def : DiagGroup<"disabled-optimization">;
|
||||
def : DiagGroup<"discard-qual">;
|
||||
|
|
|
@ -483,9 +483,12 @@ def warn_access_decl_deprecated : Warning<
|
|||
def err_access_decl : Error<
|
||||
"ISO C++11 does not allow access declarations; "
|
||||
"use using declarations instead">;
|
||||
def ext_dynamic_exception_spec : ExtWarn<
|
||||
"ISO C++1z does not allow dynamic exception specifications">,
|
||||
InGroup<DynamicExceptionSpec>, DefaultError;
|
||||
def warn_exception_spec_deprecated : Warning<
|
||||
"dynamic exception specifications are deprecated">,
|
||||
InGroup<Deprecated>, DefaultIgnore;
|
||||
InGroup<DeprecatedDynamicExceptionSpec>, DefaultIgnore;
|
||||
def note_exception_spec_deprecated : Note<"use '%0' instead">;
|
||||
def warn_deprecated_copy_operation : Warning<
|
||||
"definition of implicit copy %select{constructor|assignment operator}1 "
|
||||
|
|
|
@ -3513,7 +3513,11 @@ static void diagnoseDynamicExceptionSpecification(
|
|||
Parser &P, SourceRange Range, bool IsNoexcept) {
|
||||
if (P.getLangOpts().CPlusPlus11) {
|
||||
const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)";
|
||||
P.Diag(Range.getBegin(), diag::warn_exception_spec_deprecated) << Range;
|
||||
P.Diag(Range.getBegin(),
|
||||
P.getLangOpts().CPlusPlus1z && !IsNoexcept
|
||||
? diag::ext_dynamic_exception_spec
|
||||
: diag::warn_exception_spec_deprecated)
|
||||
<< Range;
|
||||
P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated)
|
||||
<< Replacement << FixItHint::CreateReplacement(Range, Replacement);
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ static_assert(q == &S::f);
|
|||
|
||||
|
||||
namespace std_example {
|
||||
void (*p)() throw(int);
|
||||
void (**pp)() noexcept = &p; // expected-error {{cannot initialize a variable of type 'void (**)() noexcept' with an rvalue of type 'void (**)() throw(int)'}}
|
||||
void (*p)();
|
||||
void (**pp)() noexcept = &p; // expected-error {{cannot initialize a variable of type 'void (**)() noexcept' with an rvalue of type 'void (**)()'}}
|
||||
|
||||
struct S { typedef void (*p)(); operator p(); }; // expected-note {{candidate}}
|
||||
void (*q)() noexcept = S(); // expected-error {{no viable conversion from 'std_example::S' to 'void (*)() noexcept'}}
|
||||
|
|
|
@ -276,9 +276,9 @@ namespace dr23 { // dr23: yes
|
|||
|
||||
namespace dr25 { // dr25: yes
|
||||
struct A {
|
||||
void f() throw(int);
|
||||
void f() throw(int); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
};
|
||||
void (A::*f)() throw (int);
|
||||
void (A::*f)() throw (int); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
void (A::*g)() throw () = f;
|
||||
#if __cplusplus <= 201402L
|
||||
// expected-error@-2 {{is not superset of source}}
|
||||
|
@ -286,7 +286,7 @@ namespace dr25 { // dr25: yes
|
|||
// expected-error@-4 {{different exception specifications}}
|
||||
#endif
|
||||
void (A::*g2)() throw () = 0;
|
||||
void (A::*h)() throw (int, char) = f;
|
||||
void (A::*h)() throw (int, char) = f; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
void (A::*i)() throw () = &A::f;
|
||||
#if __cplusplus <= 201402L
|
||||
// expected-error@-2 {{is not superset of source}}
|
||||
|
@ -294,7 +294,7 @@ namespace dr25 { // dr25: yes
|
|||
// expected-error@-4 {{different exception specifications}}
|
||||
#endif
|
||||
void (A::*i2)() throw () = 0;
|
||||
void (A::*j)() throw (int, char) = &A::f;
|
||||
void (A::*j)() throw (int, char) = &A::f; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
void x() {
|
||||
g2 = f;
|
||||
#if __cplusplus <= 201402L
|
||||
|
@ -1033,14 +1033,14 @@ namespace dr91 { // dr91: yes
|
|||
}
|
||||
|
||||
namespace dr92 { // dr92: 4.0 c++17
|
||||
void f() throw(int, float);
|
||||
void (*p)() throw(int) = &f;
|
||||
void f() throw(int, float); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
void (*p)() throw(int) = &f; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
#if __cplusplus <= 201402L
|
||||
// expected-error@-2 {{target exception specification is not superset of source}}
|
||||
#else
|
||||
// expected-warning@-4 {{target exception specification is not superset of source}}
|
||||
#endif
|
||||
void (*q)() throw(int);
|
||||
void (*q)() throw(int); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
void (**pp)() throw() = &q;
|
||||
#if __cplusplus <= 201402L
|
||||
// expected-error@-2 {{exception specifications are not allowed}}
|
||||
|
@ -1064,7 +1064,7 @@ namespace dr92 { // dr92: 4.0 c++17
|
|||
// expected-error@-2 {{not implicitly convertible}}
|
||||
#endif
|
||||
|
||||
template<void() throw(int)> struct Y {};
|
||||
template<void() throw(int)> struct Y {}; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
|
||||
Y<&h> yp; // ok
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
namespace dr1330 { // dr1330: 4.0 c++11
|
||||
// exception-specifications are parsed in a context where the class is complete.
|
||||
struct A {
|
||||
void f() throw(T) {}
|
||||
void f() throw(T) {} // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
|
||||
struct T {};
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
@ -16,7 +16,7 @@ namespace dr1330 { // dr1330: 4.0 c++11
|
|||
#endif
|
||||
};
|
||||
|
||||
void (A::*af1)() throw(A::T) = &A::f;
|
||||
void (A::*af1)() throw(A::T) = &A::f; // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
|
||||
void (A::*af2)() throw() = &A::f; // expected-error-re {{{{not superset|different exception spec}}}}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
@ -26,7 +26,7 @@ namespace dr1330 { // dr1330: 4.0 c++11
|
|||
// Likewise, they're instantiated separately from an enclosing class template.
|
||||
template<typename U>
|
||||
struct B {
|
||||
void f() throw(T, typename U::type) {}
|
||||
void f() throw(T, typename U::type) {} // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
|
||||
struct T {};
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
|
@ -43,7 +43,7 @@ namespace dr1330 { // dr1330: 4.0 c++11
|
|||
static const int value = true;
|
||||
};
|
||||
|
||||
void (B<P>::*bpf1)() throw(B<P>::T, int) = &B<P>::f;
|
||||
void (B<P>::*bpf1)() throw(B<P>::T, int) = &B<P>::f; // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
|
||||
#if __cplusplus < 201103L
|
||||
// expected-error@-2 {{not superset}}
|
||||
// FIXME: We only delay instantiation in C++11 onwards. In C++98, something
|
||||
|
@ -54,7 +54,7 @@ namespace dr1330 { // dr1330: 4.0 c++11
|
|||
// the "T has not yet been instantiated" error here, rather than giving
|
||||
// confusing errors later on.
|
||||
#endif
|
||||
void (B<P>::*bpf2)() throw(int) = &B<P>::f;
|
||||
void (B<P>::*bpf2)() throw(int) = &B<P>::f; // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
|
||||
#if __cplusplus <= 201402L
|
||||
// expected-error@-2 {{not superset}}
|
||||
#else
|
||||
|
@ -75,6 +75,9 @@ namespace dr1330 { // dr1330: 4.0 c++11
|
|||
#endif
|
||||
|
||||
template<typename T> int f() throw(typename T::error) { return 0; } // expected-error 1-4{{prior to '::'}} expected-note 0-1{{instantiation of}}
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 0-1{{C++1z}} expected-note@-2 0-1{{noexcept}}
|
||||
#endif
|
||||
// An exception-specification is needed even if the function is only used in
|
||||
// an unevaluated operand.
|
||||
int f1 = sizeof(f<int>()); // expected-note {{instantiation of}}
|
||||
|
@ -86,6 +89,9 @@ namespace dr1330 { // dr1330: 4.0 c++11
|
|||
|
||||
template<typename T> struct C {
|
||||
C() throw(typename T::type); // expected-error 1-2{{prior to '::'}}
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 0-1{{C++1z}} expected-note@-2 0-1{{noexcept}}
|
||||
#endif
|
||||
};
|
||||
struct D : C<void> {}; // ok
|
||||
#if __cplusplus < 201103L
|
||||
|
|
|
@ -239,6 +239,7 @@ namespace dr125 {
|
|||
}
|
||||
|
||||
namespace dr126 { // dr126: no
|
||||
#if __cplusplus <= 201402L
|
||||
struct C {};
|
||||
struct D : C {};
|
||||
struct E : private C { friend class A; friend class B; };
|
||||
|
@ -311,12 +312,15 @@ namespace dr126 { // dr126: no
|
|||
virtual void y() throw(int*); // ok
|
||||
virtual void z() throw(long); // expected-error {{more lax}}
|
||||
};
|
||||
#else
|
||||
void f() throw(int); // expected-error {{ISO C++1z does not allow}} expected-note {{use 'noexcept}}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr127 { // dr127: yes
|
||||
__extension__ typedef __decltype(sizeof(0)) size_t;
|
||||
template<typename T> struct A {
|
||||
A() throw(int);
|
||||
A() { throw 0; }
|
||||
void *operator new(size_t, const char * = 0);
|
||||
void operator delete(void *, const char *) { T::error; } // expected-error 2{{no members}}
|
||||
void operator delete(void *) { T::error; }
|
||||
|
|
|
@ -983,6 +983,9 @@ namespace dr289 { // dr289: yes
|
|||
|
||||
namespace dr294 { // dr294: no
|
||||
void f() throw(int);
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
|
||||
#endif
|
||||
int main() {
|
||||
(void)static_cast<void (*)() throw()>(f); // FIXME: ill-formed in C++14 and before
|
||||
#if __cplusplus > 201402L
|
||||
|
@ -992,12 +995,20 @@ namespace dr294 { // dr294: no
|
|||
// we reject it. In C++14 and before, this is ill-formed because an
|
||||
// exception-specification is not permitted in a type-id. In C++17, this is
|
||||
// valid because it's the inverse of a standard conversion sequence
|
||||
// containing a function pointer conversion.
|
||||
// containing a function pointer conversion. (Well, it's actually not valid
|
||||
// yet, as a static_cast is not permitted to reverse a function pointer
|
||||
// conversion, but that is being changed by core issue).
|
||||
#endif
|
||||
(void)static_cast<void (*)() throw(int)>(f); // FIXME: ill-formed in C++14 and before
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
|
||||
#endif
|
||||
|
||||
void (*p)() throw() = f; // expected-error-re {{{{not superset|different exception specification}}}}
|
||||
void (*q)() throw(int) = f;
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -508,9 +508,18 @@ namespace dr437 { // dr437: sup 1308
|
|||
template<typename U> struct T : U {};
|
||||
struct S {
|
||||
void f() throw(S);
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
|
||||
#endif
|
||||
void g() throw(T<S>);
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
|
||||
#endif
|
||||
struct U;
|
||||
void h() throw(U);
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
|
||||
#endif
|
||||
struct U {};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -953,6 +953,9 @@ namespace dr591 { // dr591: no
|
|||
namespace dr595 { // dr595: dup 1330
|
||||
template<class T> struct X {
|
||||
void f() throw(T) {}
|
||||
#if __cplusplus > 201402L
|
||||
// expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
|
||||
#endif
|
||||
};
|
||||
struct S {
|
||||
X<S> xs;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c++1z -verify %s -fexceptions -fcxx-exceptions
|
||||
// RUN: %clang_cc1 -std=c++1z -verify %s -fexceptions -fcxx-exceptions -Wno-dynamic-exception-spec
|
||||
|
||||
struct X {};
|
||||
struct Y : X {};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s --check-prefix CHECK --check-prefix CHECK-CXX11
|
||||
// RUN: %clang_cc1 -std=c++1z -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s --check-prefix CHECK --check-prefix CHECK-CXX17
|
||||
// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -Wno-dynamic-exception-spec | FileCheck %s --check-prefix CHECK --check-prefix CHECK-CXX11
|
||||
// RUN: %clang_cc1 -std=c++1z -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -Wno-dynamic-exception-spec | FileCheck %s --check-prefix CHECK --check-prefix CHECK-CXX17
|
||||
|
||||
// CHECK: define {{.*}} @_Z1aPFivE(
|
||||
void a(int() throw(int, float)) {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s
|
||||
// RUN: %clang_cc1 -std=c++1z -verify -fexceptions -fcxx-exceptions %s
|
||||
// RUN: %clang_cc1 -std=c++1z -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
|
||||
|
|
|
@ -10,10 +10,14 @@
|
|||
void g() throw();
|
||||
void h() throw(int);
|
||||
void i() throw(...);
|
||||
#if __cplusplus >= 201103L
|
||||
#if __cplusplus > 201402L
|
||||
// expected-warning@-4 {{dynamic exception specifications are deprecated}} expected-note@-4 {{use 'noexcept' instead}}
|
||||
// expected-warning@-4 {{dynamic exception specifications are deprecated}} expected-note@-4 {{use 'noexcept(false)' instead}}
|
||||
// expected-warning@-4 {{dynamic exception specifications are deprecated}} expected-note@-4 {{use 'noexcept(false)' instead}}
|
||||
// expected-error@-4 {{ISO C++1z does not allow dynamic exception specifications}} expected-note@-4 {{use 'noexcept(false)' instead}}
|
||||
// expected-error@-4 {{ISO C++1z does not allow dynamic exception specifications}} expected-note@-4 {{use 'noexcept(false)' instead}}
|
||||
#elif __cplusplus >= 201103L
|
||||
// expected-warning@-8 {{dynamic exception specifications are deprecated}} expected-note@-8 {{use 'noexcept' instead}}
|
||||
// expected-warning@-8 {{dynamic exception specifications are deprecated}} expected-note@-8 {{use 'noexcept(false)' instead}}
|
||||
// expected-warning@-8 {{dynamic exception specifications are deprecated}} expected-note@-8 {{use 'noexcept(false)' instead}}
|
||||
#endif
|
||||
|
||||
void stuff() {
|
||||
|
|
|
@ -740,7 +740,7 @@ as the draft C++1z standard evolves.
|
|||
<tr>
|
||||
<td>Removing deprecated dynamic exception specifications</td>
|
||||
<td><a href="http://wg21.link/p0003r5">P0003R5</a></td>
|
||||
<td class="none" align="center">No</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pack expansions in <em>using-declarations</em></td>
|
||||
|
|
Loading…
Reference in New Issue