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