/ test / catch_multi_level_pointer.pass.cpp
catch_multi_level_pointer.pass.cpp
  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: 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  }