1*eb8650a7SLouis Dionne //===----------------------------------------------------------------------===//
21b00fc5dSEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61b00fc5dSEric Fiselier //
71b00fc5dSEric Fiselier //===----------------------------------------------------------------------===//
81b00fc5dSEric Fiselier 
98c61114cSLouis Dionne // UNSUPPORTED: no-exceptions
1057e446daSAsiri Rathnayake 
1160ba1fefSLouis Dionne // 1b00fc5d8133 made it in the dylib in macOS 10.11
12c360553cSLouis Dionne // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10}}
1360ba1fefSLouis Dionne 
141b00fc5dSEric Fiselier #include <cassert>
15cc69d211SLouis Dionne #include <cstdio>
161b00fc5dSEric Fiselier #include <cstdlib>
171b00fc5dSEric Fiselier 
181b00fc5dSEric Fiselier // Roll our own assertion macro to get better error messages out of the tests.
191b00fc5dSEric Fiselier // In particular on systems that don't use __PRETTY_FUNCTION__ in assertions.
201b00fc5dSEric Fiselier #define my_assert(pred, msg) do_assert(pred, msg, __LINE__, __PRETTY_FUNCTION__)
211b00fc5dSEric Fiselier 
do_assert(bool assert_passed,const char * msg,int line,const char * func)221b00fc5dSEric Fiselier void do_assert(bool assert_passed, const char* msg, int line, const char* func) {
23cc69d211SLouis Dionne   if (assert_passed)
24cc69d211SLouis Dionne     return;
25cc69d211SLouis Dionne   std::printf("%s:%d %s: Assertion Failed '%s'\n\n", __FILE__, line, func, msg);
261b00fc5dSEric Fiselier   std::abort();
271b00fc5dSEric Fiselier }
281b00fc5dSEric Fiselier 
291b00fc5dSEric Fiselier struct A {};
301b00fc5dSEric Fiselier struct Base {};
311b00fc5dSEric Fiselier struct Derived : public Base {};
321b00fc5dSEric Fiselier 
331b00fc5dSEric Fiselier template <class To>
test_conversion(To)341b00fc5dSEric Fiselier bool test_conversion(To) { return true; }
351b00fc5dSEric Fiselier 
361b00fc5dSEric Fiselier template <class To>
test_conversion(...)371b00fc5dSEric Fiselier bool test_conversion(...) { return false; }
381b00fc5dSEric Fiselier 
391b00fc5dSEric Fiselier template <class Pointer>
401b00fc5dSEric Fiselier struct CreatePointer {
operator ()CreatePointer411b00fc5dSEric Fiselier   Pointer operator()() const {
421b00fc5dSEric Fiselier       return (Pointer)0;
431b00fc5dSEric Fiselier   }
441b00fc5dSEric Fiselier };
451b00fc5dSEric Fiselier 
461b00fc5dSEric Fiselier template <class Tp>
471b00fc5dSEric Fiselier struct CreatePointer<Tp*> {
operator ()CreatePointer481b00fc5dSEric Fiselier   Tp* operator()() const {
491b00fc5dSEric Fiselier       return (Tp*)42;
501b00fc5dSEric Fiselier   }
511b00fc5dSEric Fiselier };
521b00fc5dSEric Fiselier 
531b00fc5dSEric Fiselier template <class Throw, class Catch>
catch_pointer_test()541b00fc5dSEric Fiselier void catch_pointer_test() {
551b00fc5dSEric Fiselier   Throw throw_ptr = CreatePointer<Throw>()();
561b00fc5dSEric Fiselier   // Use the compiler to determine if the exception of type Throw can be
571b00fc5dSEric Fiselier   // implicitly converted to type Catch.
581b00fc5dSEric Fiselier   const bool can_convert = test_conversion<Catch>(throw_ptr);
591b00fc5dSEric Fiselier   try {
601b00fc5dSEric Fiselier     throw throw_ptr;
611b00fc5dSEric Fiselier     assert(false);
621b00fc5dSEric Fiselier   } catch (Catch catch_ptr) {
631b00fc5dSEric Fiselier     Catch catch2 = CreatePointer<Catch>()();
641b00fc5dSEric Fiselier     my_assert(can_convert, "non-convertible type incorrectly caught");
651b00fc5dSEric Fiselier     my_assert(catch_ptr == catch2,
661b00fc5dSEric Fiselier               "Thrown pointer does not match caught ptr");
671b00fc5dSEric Fiselier   } catch (...) {
681b00fc5dSEric Fiselier     my_assert(!can_convert, "convertible type incorrectly not caught");
691b00fc5dSEric Fiselier   }
701b00fc5dSEric Fiselier }
711b00fc5dSEric Fiselier 
721b00fc5dSEric Fiselier // Generate CV qualified pointer typedefs.
731b00fc5dSEric Fiselier template <class Tp, bool First = false>
741b00fc5dSEric Fiselier struct TestTypes {
751b00fc5dSEric Fiselier   typedef Tp* Type;
761b00fc5dSEric Fiselier   typedef Tp const* CType;
771b00fc5dSEric Fiselier   typedef Tp volatile* VType;
781b00fc5dSEric Fiselier   typedef Tp const volatile* CVType;
791b00fc5dSEric Fiselier };
801b00fc5dSEric Fiselier 
811b00fc5dSEric Fiselier // Special case for cv-qualifying a pointer-to-member without adding an extra
821b00fc5dSEric Fiselier // pointer to it.
831b00fc5dSEric Fiselier template <class Member, class Class>
841b00fc5dSEric Fiselier struct TestTypes<Member Class::*, true> {
851b00fc5dSEric Fiselier   typedef Member (Class::*Type);
861b00fc5dSEric Fiselier   typedef const Member (Class::*CType);
871b00fc5dSEric Fiselier   typedef volatile Member (Class::*VType);
881b00fc5dSEric Fiselier   typedef const volatile Member (Class::*CVType);
891b00fc5dSEric Fiselier };
901b00fc5dSEric Fiselier 
911b00fc5dSEric Fiselier template <class Throw, class Catch, int level, bool first = false>
921b00fc5dSEric Fiselier struct generate_tests_imp {
931b00fc5dSEric Fiselier   typedef TestTypes<Throw, first> ThrowTypes;
941b00fc5dSEric Fiselier   typedef TestTypes<Catch, first> CatchTypes;
operator ()generate_tests_imp951b00fc5dSEric Fiselier   void operator()() {
961b00fc5dSEric Fiselier       typedef typename ThrowTypes::Type Type;
971b00fc5dSEric Fiselier       typedef typename ThrowTypes::CType CType;
981b00fc5dSEric Fiselier       typedef typename ThrowTypes::VType VType;
991b00fc5dSEric Fiselier       typedef typename ThrowTypes::CVType CVType;
1001b00fc5dSEric Fiselier 
1011b00fc5dSEric Fiselier       run_catch_tests<Type>();
1021b00fc5dSEric Fiselier       run_catch_tests<CType>();
1031b00fc5dSEric Fiselier       run_catch_tests<VType>();
1041b00fc5dSEric Fiselier       run_catch_tests<CVType>();
1051b00fc5dSEric Fiselier   }
1061b00fc5dSEric Fiselier 
1071b00fc5dSEric Fiselier   template <class ThrowTp>
run_catch_testsgenerate_tests_imp1081b00fc5dSEric Fiselier   void run_catch_tests() {
1091b00fc5dSEric Fiselier       typedef typename CatchTypes::Type Type;
1101b00fc5dSEric Fiselier       typedef typename CatchTypes::CType CType;
1111b00fc5dSEric Fiselier       typedef typename CatchTypes::VType VType;
1121b00fc5dSEric Fiselier       typedef typename CatchTypes::CVType CVType;
1131b00fc5dSEric Fiselier 
1141b00fc5dSEric Fiselier       catch_pointer_test<ThrowTp, Type>();
1151b00fc5dSEric Fiselier       catch_pointer_test<ThrowTp, CType>();
1161b00fc5dSEric Fiselier       catch_pointer_test<ThrowTp, VType>();
1171b00fc5dSEric Fiselier       catch_pointer_test<ThrowTp, CVType>();
1181b00fc5dSEric Fiselier 
1191b00fc5dSEric Fiselier       generate_tests_imp<ThrowTp, Type, level-1>()();
1201b00fc5dSEric Fiselier       generate_tests_imp<ThrowTp, CType, level-1>()();
1211b00fc5dSEric Fiselier       generate_tests_imp<ThrowTp, VType, level-1>()();
1221b00fc5dSEric Fiselier       generate_tests_imp<ThrowTp, CVType, level-1>()();
1231b00fc5dSEric Fiselier   }
1241b00fc5dSEric Fiselier };
1251b00fc5dSEric Fiselier 
1261b00fc5dSEric Fiselier template <class Throw, class Catch, bool first>
1271b00fc5dSEric Fiselier struct generate_tests_imp<Throw, Catch, 0, first> {
operator ()generate_tests_imp1281b00fc5dSEric Fiselier   void operator()() {
1291b00fc5dSEric Fiselier       catch_pointer_test<Throw, Catch>();
1301b00fc5dSEric Fiselier   }
1311b00fc5dSEric Fiselier };
1321b00fc5dSEric Fiselier 
1331b00fc5dSEric Fiselier template <class Throw, class Catch, int level>
1341b00fc5dSEric Fiselier struct generate_tests : generate_tests_imp<Throw, Catch, level, true> {};
1351b00fc5dSEric Fiselier 
main(int,char **)136504bc07dSLouis Dionne int main(int, char**)
1371b00fc5dSEric Fiselier {
1381b00fc5dSEric Fiselier   generate_tests<int, int, 3>()();
1391b00fc5dSEric Fiselier   generate_tests<Base, Derived, 2>()();
1401b00fc5dSEric Fiselier   generate_tests<Derived, Base, 2>()();
1411b00fc5dSEric Fiselier   generate_tests<int, void, 2>()();
1421b00fc5dSEric Fiselier   generate_tests<void, int, 2>()();
1431b00fc5dSEric Fiselier 
1441b00fc5dSEric Fiselier   generate_tests<int A::*, int A::*, 3>()();
1451b00fc5dSEric Fiselier   generate_tests<int A::*, void, 2>()();
1461b00fc5dSEric Fiselier   generate_tests<void, int A::*, 2>()();
147504bc07dSLouis Dionne 
148504bc07dSLouis Dionne   return 0;
1491b00fc5dSEric Fiselier }
150