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