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