Home | History | Annotate | Download | only in test
      1 //===--------------------- catch_pointer_nullptr.cpp ----------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // UNSUPPORTED: libcxxabi-no-exceptions
     11 
     12 #include <cassert>
     13 #include <cstdlib>
     14 #include <iostream>
     15 
     16 // Roll our own assertion macro to get better error messages out of the tests.
     17 // In particular on systems that don't use __PRETTY_FUNCTION__ in assertions.
     18 #define my_assert(pred, msg) do_assert(pred, msg, __LINE__, __PRETTY_FUNCTION__)
     19 
     20 void do_assert(bool assert_passed, const char* msg, int line, const char* func) {
     21   if (assert_passed) return;
     22   std::cerr << __FILE__ << ":" << line << " " << func
     23             << ": Assertion Failed `" << msg << "'\n\n";
     24   std::abort();
     25 }
     26 
     27 struct A {};
     28 struct Base {};
     29 struct Derived : public Base {};
     30 
     31 template <class To>
     32 bool test_conversion(To) { return true; }
     33 
     34 template <class To>
     35 bool test_conversion(...) { return false; }
     36 
     37 template <class Pointer>
     38 struct CreatePointer {
     39   Pointer operator()() const {
     40       return (Pointer)0;
     41   }
     42 };
     43 
     44 template <class Tp>
     45 struct CreatePointer<Tp*> {
     46   Tp* operator()() const {
     47       return (Tp*)42;
     48   }
     49 };
     50 
     51 template <class Throw, class Catch>
     52 void catch_pointer_test() {
     53   Throw throw_ptr = CreatePointer<Throw>()();
     54   // Use the compiler to determine if the exception of type Throw can be
     55   // implicitly converted to type Catch.
     56   const bool can_convert = test_conversion<Catch>(throw_ptr);
     57   try {
     58     throw throw_ptr;
     59     assert(false);
     60   } catch (Catch catch_ptr) {
     61     Catch catch2 = CreatePointer<Catch>()();
     62     my_assert(can_convert, "non-convertible type incorrectly caught");
     63     my_assert(catch_ptr == catch2,
     64               "Thrown pointer does not match caught ptr");
     65   } catch (...) {
     66     my_assert(!can_convert, "convertible type incorrectly not caught");
     67   }
     68 }
     69 
     70 // Generate CV qualified pointer typedefs.
     71 template <class Tp, bool First = false>
     72 struct TestTypes {
     73   typedef Tp* Type;
     74   typedef Tp const* CType;
     75   typedef Tp volatile* VType;
     76   typedef Tp const volatile* CVType;
     77 };
     78 
     79 // Special case for cv-qualifying a pointer-to-member without adding an extra
     80 // pointer to it.
     81 template <class Member, class Class>
     82 struct TestTypes<Member Class::*, true> {
     83   typedef Member (Class::*Type);
     84   typedef const Member (Class::*CType);
     85   typedef volatile Member (Class::*VType);
     86   typedef const volatile Member (Class::*CVType);
     87 };
     88 
     89 template <class Throw, class Catch, int level, bool first = false>
     90 struct generate_tests_imp {
     91   typedef TestTypes<Throw, first> ThrowTypes;
     92   typedef TestTypes<Catch, first> CatchTypes;
     93   void operator()() {
     94       typedef typename ThrowTypes::Type Type;
     95       typedef typename ThrowTypes::CType CType;
     96       typedef typename ThrowTypes::VType VType;
     97       typedef typename ThrowTypes::CVType CVType;
     98 
     99       run_catch_tests<Type>();
    100       run_catch_tests<CType>();
    101       run_catch_tests<VType>();
    102       run_catch_tests<CVType>();
    103   }
    104 
    105   template <class ThrowTp>
    106   void run_catch_tests() {
    107       typedef typename CatchTypes::Type Type;
    108       typedef typename CatchTypes::CType CType;
    109       typedef typename CatchTypes::VType VType;
    110       typedef typename CatchTypes::CVType CVType;
    111 
    112       catch_pointer_test<ThrowTp, Type>();
    113       catch_pointer_test<ThrowTp, CType>();
    114       catch_pointer_test<ThrowTp, VType>();
    115       catch_pointer_test<ThrowTp, CVType>();
    116 
    117       generate_tests_imp<ThrowTp, Type, level-1>()();
    118       generate_tests_imp<ThrowTp, CType, level-1>()();
    119       generate_tests_imp<ThrowTp, VType, level-1>()();
    120       generate_tests_imp<ThrowTp, CVType, level-1>()();
    121   }
    122 };
    123 
    124 template <class Throw, class Catch, bool first>
    125 struct generate_tests_imp<Throw, Catch, 0, first> {
    126   void operator()() {
    127       catch_pointer_test<Throw, Catch>();
    128   }
    129 };
    130 
    131 template <class Throw, class Catch, int level>
    132 struct generate_tests : generate_tests_imp<Throw, Catch, level, true> {};
    133 
    134 int main()
    135 {
    136   generate_tests<int, int, 3>()();
    137   generate_tests<Base, Derived, 2>()();
    138   generate_tests<Derived, Base, 2>()();
    139   generate_tests<int, void, 2>()();
    140   generate_tests<void, int, 2>()();
    141 
    142   generate_tests<int A::*, int A::*, 3>()();
    143   generate_tests<int A::*, void, 2>()();
    144   generate_tests<void, int A::*, 2>()();
    145 }
    146