forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			465 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			465 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
// RUN: %clang_cc1 %s  -fdelayed-template-parsing -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec -std=c++17
 | 
						|
struct A_ShouldDiag {
 | 
						|
  ~A_ShouldDiag(); // implicitly noexcept(true)
 | 
						|
};
 | 
						|
A_ShouldDiag::~A_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}}
 | 
						|
  throw 1; // expected-warning {{has a non-throwing exception specification but can still throw}}
 | 
						|
}
 | 
						|
struct B_ShouldDiag {
 | 
						|
  int i;
 | 
						|
  ~B_ShouldDiag() noexcept(true) {} //no disg, no throw stmt
 | 
						|
};
 | 
						|
struct R_ShouldDiag : A_ShouldDiag {
 | 
						|
  B_ShouldDiag b;
 | 
						|
  ~R_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
  __attribute__((nothrow)) R_ShouldDiag() {// expected-note {{function declared non-throwing here}}
 | 
						|
    throw 1;// expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
  void __attribute__((nothrow)) SomeThrow() {// expected-note {{function declared non-throwing here}}
 | 
						|
   throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
  void __declspec(nothrow) SomeDeclspecThrow() {// expected-note {{function declared non-throwing here}}
 | 
						|
   throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
struct M_ShouldNotDiag {
 | 
						|
  B_ShouldDiag b;
 | 
						|
  ~M_ShouldNotDiag() noexcept(false);
 | 
						|
};
 | 
						|
 | 
						|
M_ShouldNotDiag::~M_ShouldNotDiag() noexcept(false) {
 | 
						|
  throw 1;
 | 
						|
}
 | 
						|
 | 
						|
struct N_ShouldDiag {
 | 
						|
  B_ShouldDiag b;
 | 
						|
  ~N_ShouldDiag(); //implicitly noexcept(true)
 | 
						|
};
 | 
						|
 | 
						|
N_ShouldDiag::~N_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}}
 | 
						|
  throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
}
 | 
						|
struct X_ShouldDiag {
 | 
						|
  B_ShouldDiag b;
 | 
						|
  ~X_ShouldDiag() noexcept { // expected-note  {{destructor has a non-throwing exception}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
struct Y_ShouldDiag : A_ShouldDiag {
 | 
						|
  ~Y_ShouldDiag() noexcept(true) { // expected-note  {{destructor has a non-throwing exception specification}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
struct C_ShouldNotDiag {
 | 
						|
  int i;
 | 
						|
  ~C_ShouldNotDiag() noexcept(false) {}
 | 
						|
};
 | 
						|
struct D_ShouldNotDiag {
 | 
						|
  C_ShouldNotDiag c;
 | 
						|
  ~D_ShouldNotDiag() { //implicitly noexcept(false)
 | 
						|
    throw 1;
 | 
						|
  }
 | 
						|
};
 | 
						|
struct E_ShouldNotDiag {
 | 
						|
  C_ShouldNotDiag c;
 | 
						|
  ~E_ShouldNotDiag(); //implicitly noexcept(false)
 | 
						|
};
 | 
						|
E_ShouldNotDiag::~E_ShouldNotDiag() //implicitly noexcept(false)
 | 
						|
{
 | 
						|
  throw 1;
 | 
						|
}
 | 
						|
 | 
						|
template <typename T>
 | 
						|
class A1_ShouldDiag {
 | 
						|
  T b;
 | 
						|
 | 
						|
public:
 | 
						|
  ~A1_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
template <typename T>
 | 
						|
struct B1_ShouldDiag {
 | 
						|
  T i;
 | 
						|
  ~B1_ShouldDiag() noexcept(true) {}
 | 
						|
};
 | 
						|
template <typename T>
 | 
						|
struct R1_ShouldDiag : A1_ShouldDiag<T> //expected-note {{in instantiation of member function}}
 | 
						|
{
 | 
						|
  B1_ShouldDiag<T> b;
 | 
						|
  ~R1_ShouldDiag() { // expected-note  {{destructor has a implicit non-throwing exception specification}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
template <typename T>
 | 
						|
struct S1_ShouldDiag : A1_ShouldDiag<T> {
 | 
						|
  B1_ShouldDiag<T> b;
 | 
						|
  ~S1_ShouldDiag() noexcept { // expected-note  {{destructor has a non-throwing exception specification}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
void operator delete(void *ptr) noexcept { // expected-note  {{deallocator has a non-throwing exception specification}}
 | 
						|
  throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
}
 | 
						|
struct except_fun {
 | 
						|
  static const bool i = false;
 | 
						|
};
 | 
						|
struct noexcept_fun {
 | 
						|
  static const bool i = true;
 | 
						|
};
 | 
						|
template <typename T>
 | 
						|
struct dependent_warn {
 | 
						|
  ~dependent_warn() noexcept(T::i) {
 | 
						|
    throw 1;
 | 
						|
  }
 | 
						|
};
 | 
						|
template <typename T>
 | 
						|
struct dependent_warn_noexcept {
 | 
						|
  ~dependent_warn_noexcept() noexcept(T::i) { // expected-note  {{destructor has a non-throwing exception specification}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
template <typename T>
 | 
						|
struct dependent_warn_both {
 | 
						|
  ~dependent_warn_both() noexcept(T::i) { // expected-note  {{destructor has a non-throwing exception specification}}
 | 
						|
    throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
void foo() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
}
 | 
						|
struct Throws {
 | 
						|
  ~Throws() noexcept(false);
 | 
						|
};
 | 
						|
 | 
						|
struct ShouldDiagnose {
 | 
						|
  Throws T;
 | 
						|
  ~ShouldDiagnose() noexcept { //expected-note {{destructor has a non-throwing exception specification}}
 | 
						|
    throw; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
};
 | 
						|
struct ShouldNotDiagnose {
 | 
						|
  Throws T;
 | 
						|
  ~ShouldNotDiagnose() {
 | 
						|
    throw;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
void bar_ShouldNotDiag() noexcept {
 | 
						|
  try {
 | 
						|
    throw 1;
 | 
						|
  } catch (...) {
 | 
						|
  }
 | 
						|
}
 | 
						|
void f_ShouldNotDiag() noexcept {
 | 
						|
  try {
 | 
						|
    throw 12;
 | 
						|
  } catch (int) {
 | 
						|
  }
 | 
						|
}
 | 
						|
void g_ShouldNotDiag() noexcept {
 | 
						|
  try {
 | 
						|
    throw 12;
 | 
						|
  } catch (...) {
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void h_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  try {
 | 
						|
    throw 12; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  } catch (const char *) {
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void i_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  try {
 | 
						|
    throw 12;
 | 
						|
  } catch (int) {
 | 
						|
    throw; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
}
 | 
						|
void j_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  try {
 | 
						|
    throw 12;
 | 
						|
  } catch (int) {
 | 
						|
    throw "haha"; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void k_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  try {
 | 
						|
    throw 12;
 | 
						|
  } catch (...) {
 | 
						|
    throw; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void loo_ShouldDiag(int i) noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  if (i)
 | 
						|
    try {
 | 
						|
      throw 12;
 | 
						|
    } catch (int) {
 | 
						|
      throw "haha"; //expected-warning {{has a non-throwing exception specification but}}
 | 
						|
    }
 | 
						|
  i = 10;
 | 
						|
}
 | 
						|
 | 
						|
void loo1_ShouldNotDiag() noexcept {
 | 
						|
  if (0)
 | 
						|
    throw 12;
 | 
						|
}
 | 
						|
 | 
						|
void loo2_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  if (1)
 | 
						|
    throw 12; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
}
 | 
						|
struct S {};
 | 
						|
 | 
						|
void l_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  try {
 | 
						|
    throw S{}; //expected-warning {{has a non-throwing exception specification but}}
 | 
						|
  } catch (S *s) {
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void m_ShouldNotDiag() noexcept {
 | 
						|
  try {
 | 
						|
    const S &s = S{};
 | 
						|
    throw s;
 | 
						|
  } catch (S s) {
 | 
						|
  }
 | 
						|
}
 | 
						|
void n_ShouldNotDiag() noexcept {
 | 
						|
  try {
 | 
						|
    S s = S{};
 | 
						|
    throw s;
 | 
						|
  } catch (const S &s) {
 | 
						|
  }
 | 
						|
}
 | 
						|
// As seen in p34973, this should not throw the warning.  If there is an active
 | 
						|
// exception, catch(...) catches everything. 
 | 
						|
void o_ShouldNotDiag() noexcept {
 | 
						|
  try {
 | 
						|
    throw;
 | 
						|
  } catch (...) {
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void p_ShouldNotDiag() noexcept {
 | 
						|
  // Don't warn here: it's possible that the user arranges to only call this
 | 
						|
  // when the active exception is of type 'int'.
 | 
						|
  try {
 | 
						|
    throw;
 | 
						|
  } catch (int){
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void q_ShouldNotDiag() noexcept {
 | 
						|
  try {
 | 
						|
    throw;
 | 
						|
  } catch (int){
 | 
						|
  } catch (...){
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#define NOEXCEPT noexcept
 | 
						|
void with_macro() NOEXCEPT { //expected-note {{function declared non-throwing here}}
 | 
						|
  throw 1; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
}
 | 
						|
 | 
						|
void with_try_block() try {
 | 
						|
  throw 2;
 | 
						|
} catch (...) {
 | 
						|
}
 | 
						|
 | 
						|
void with_try_block1() noexcept try { //expected-note {{function declared non-throwing here}}
 | 
						|
  throw 2; // expected-warning {{has a non-throwing exception specification but}}
 | 
						|
} catch (char *) {
 | 
						|
}
 | 
						|
 | 
						|
namespace derived {
 | 
						|
struct B {};
 | 
						|
struct D: B {};
 | 
						|
void goodPlain() noexcept {
 | 
						|
  try {
 | 
						|
    throw D();
 | 
						|
  } catch (B) {}
 | 
						|
}
 | 
						|
void goodReference() noexcept {
 | 
						|
  try {
 | 
						|
    throw D();
 | 
						|
  } catch (B &) {}
 | 
						|
}
 | 
						|
void goodPointer() noexcept {
 | 
						|
  D d;
 | 
						|
  try {
 | 
						|
    throw &d;
 | 
						|
  } catch (B *) {}
 | 
						|
}
 | 
						|
void badPlain() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  try {
 | 
						|
    throw B(); // expected-warning {{'badPlain' has a non-throwing exception specification but can still throw}}
 | 
						|
  } catch (D) {}
 | 
						|
}
 | 
						|
void badReference() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  try {
 | 
						|
    throw B(); // expected-warning {{'badReference' has a non-throwing exception specification but can still throw}}
 | 
						|
  } catch (D &) {}
 | 
						|
}
 | 
						|
void badPointer() noexcept { //expected-note {{function declared non-throwing here}}
 | 
						|
  B b;
 | 
						|
  try {
 | 
						|
    throw &b; // expected-warning {{'badPointer' has a non-throwing exception specification but can still throw}}
 | 
						|
  } catch (D *) {}
 | 
						|
}
 | 
						|
}
 | 
						|
 | 
						|
int main() {
 | 
						|
  R1_ShouldDiag<int> o; //expected-note {{in instantiation of member function}}
 | 
						|
  S1_ShouldDiag<int> b; //expected-note {{in instantiation of member function}}
 | 
						|
  dependent_warn<except_fun> f;
 | 
						|
  dependent_warn_noexcept<noexcept_fun> f1; //expected-note {{in instantiation of member function}}
 | 
						|
  dependent_warn_both<except_fun> f2;
 | 
						|
  dependent_warn_both<noexcept_fun> f3; //expected-note {{in instantiation of member function}}
 | 
						|
  ShouldDiagnose obj;
 | 
						|
  ShouldNotDiagnose obj1;
 | 
						|
}
 | 
						|
 | 
						|
namespace ExceptionInNamespace {
 | 
						|
  namespace N {
 | 
						|
    struct E {};
 | 
						|
  }
 | 
						|
  void run() throw() {
 | 
						|
    try {
 | 
						|
      throw N::E();
 | 
						|
    } catch (const N::E &e) {
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
namespace HandlerSpecialCases {
 | 
						|
  struct A {};
 | 
						|
  using CA = const A;
 | 
						|
 | 
						|
  struct B : A {};
 | 
						|
  using CB = const B;
 | 
						|
 | 
						|
  struct AmbigBase {};
 | 
						|
  struct AmbigMiddle : AmbigBase {};
 | 
						|
  struct AmbigDerived : AmbigBase, AmbigMiddle {}; // expected-warning {{inaccessible}}
 | 
						|
 | 
						|
  struct PrivateBase {};
 | 
						|
  struct PrivateDerived : private PrivateBase { friend void bad3() throw(); };
 | 
						|
 | 
						|
  void good() throw() {
 | 
						|
    try { throw CA(); } catch (volatile A&) {}
 | 
						|
    try { throw B(); } catch (A&) {}
 | 
						|
    try { throw B(); } catch (const volatile A&) {}
 | 
						|
    try { throw CB(); } catch (A&) {}
 | 
						|
    try { throw (int*)0; } catch (void* const volatile) {}
 | 
						|
    try { throw (int*)0; } catch (void* const &) {}
 | 
						|
    try { throw (B*)0; } catch (A*) {}
 | 
						|
    try { throw (B*)0; } catch (A* const &) {}
 | 
						|
    try { throw (void(*)() noexcept)0; } catch (void (*)()) {}
 | 
						|
    try { throw (void(*)() noexcept)0; } catch (void (*const &)()) {}
 | 
						|
    try { throw (int**)0; } catch (const int * const*) {}
 | 
						|
    try { throw (int**)0; } catch (const int * const* const&) {}
 | 
						|
    try { throw nullptr; } catch (int*) {}
 | 
						|
    try { throw nullptr; } catch (int* const&) {}
 | 
						|
  }
 | 
						|
 | 
						|
  void bad1() throw() { // expected-note {{here}}
 | 
						|
    try { throw A(); } catch (const B&) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad2() throw() { // expected-note {{here}}
 | 
						|
    try { throw AmbigDerived(); } catch (const AmbigBase&) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad3() throw() { // expected-note {{here}}
 | 
						|
    try { throw PrivateDerived(); } catch (const PrivateBase&) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad4() throw() { // expected-note {{here}}
 | 
						|
    try { throw (int*)0; } catch (void* &) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad5() throw() { // expected-note {{here}}
 | 
						|
    try { throw (int*)0; } catch (void* const volatile &) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad6() throw() { // expected-note {{here}}
 | 
						|
    try { throw (int* volatile)0; } catch (void* const volatile &) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad7() throw() { // expected-note {{here}}
 | 
						|
    try { throw (AmbigDerived*)0; } catch (AmbigBase*) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad8() throw() { // expected-note {{here}}
 | 
						|
    try { throw (PrivateDerived*)0; } catch (PrivateBase*) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad9() throw() { // expected-note {{here}}
 | 
						|
    try { throw (B*)0; } catch (A* &) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad10() throw() { // expected-note {{here}}
 | 
						|
    try { throw (void(*)())0; } catch (void (*)() noexcept) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad11() throw() { // expected-note {{here}}
 | 
						|
    try { throw (int**)0; } catch (const int **) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
  void bad12() throw() { // expected-note {{here}}
 | 
						|
    try { throw nullptr; } catch (int) {} // expected-warning {{still throw}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
namespace NestedTry {
 | 
						|
  void f() noexcept {
 | 
						|
    try {
 | 
						|
      try {
 | 
						|
        throw 0;
 | 
						|
      } catch (float) {}
 | 
						|
    } catch (int) {}
 | 
						|
  }
 | 
						|
 | 
						|
  struct A { [[noreturn]] ~A(); };
 | 
						|
 | 
						|
  void g() noexcept { // expected-note {{here}}
 | 
						|
    try {
 | 
						|
      try {
 | 
						|
        throw 0; // expected-warning {{still throw}}
 | 
						|
      } catch (float) {}
 | 
						|
    } catch (const char*) {}
 | 
						|
  }
 | 
						|
 | 
						|
  void h() noexcept { // expected-note {{here}}
 | 
						|
    try {
 | 
						|
      try {
 | 
						|
        throw 0;
 | 
						|
      } catch (float) {}
 | 
						|
    } catch (int) {
 | 
						|
      throw; // expected-warning {{still throw}}
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // FIXME: Ideally, this should still warn; we can track which types are
 | 
						|
  // potentially thrown by the rethrow.
 | 
						|
  void i() noexcept {
 | 
						|
    try {
 | 
						|
      try {
 | 
						|
        throw 0;
 | 
						|
      } catch (int) {
 | 
						|
        throw;
 | 
						|
      }
 | 
						|
    } catch (float) {}
 | 
						|
  }
 | 
						|
 | 
						|
  // FIXME: Ideally, this should not warn: the second catch block is
 | 
						|
  // unreachable.
 | 
						|
  void j() noexcept { // expected-note {{here}}
 | 
						|
    try {
 | 
						|
      try {
 | 
						|
        throw 0;
 | 
						|
      } catch (int) {}
 | 
						|
    } catch (float) {
 | 
						|
      throw; // expected-warning {{still throw}}
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |