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