summaryrefslogtreecommitdiff
path: root/test/catch_multi_level_pointer.pass.cpp
blob: 770cf6b24f040d416b3cd7278cc97aeed7811d0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//===--------------------- catch_pointer_nullptr.cpp ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: libcxxabi-no-exceptions

#include <cassert>
#include <cstdlib>
#include <iostream>

// Roll our own assertion macro to get better error messages out of the tests.
// In particular on systems that don't use __PRETTY_FUNCTION__ in assertions.
#define my_assert(pred, msg) do_assert(pred, msg, __LINE__, __PRETTY_FUNCTION__)

void do_assert(bool assert_passed, const char* msg, int line, const char* func) {
  if (assert_passed) return;
  std::cerr << __FILE__ << ":" << line << " " << func
            << ": Assertion Failed `" << msg << "'\n\n";
  std::abort();
}

struct A {};
struct Base {};
struct Derived : public Base {};

template <class To>
bool test_conversion(To) { return true; }

template <class To>
bool test_conversion(...) { return false; }

template <class Pointer>
struct CreatePointer {
  Pointer operator()() const {
      return (Pointer)0;
  }
};

template <class Tp>
struct CreatePointer<Tp*> {
  Tp* operator()() const {
      return (Tp*)42;
  }
};

template <class Throw, class Catch>
void catch_pointer_test() {
  Throw throw_ptr = CreatePointer<Throw>()();
  // Use the compiler to determine if the exception of type Throw can be
  // implicitly converted to type Catch.
  const bool can_convert = test_conversion<Catch>(throw_ptr);
  try {
    throw throw_ptr;
    assert(false);
  } catch (Catch catch_ptr) {
    Catch catch2 = CreatePointer<Catch>()();
    my_assert(can_convert, "non-convertible type incorrectly caught");
    my_assert(catch_ptr == catch2,
              "Thrown pointer does not match caught ptr");
  } catch (...) {
    my_assert(!can_convert, "convertible type incorrectly not caught");
  }
}

// Generate CV qualified pointer typedefs.
template <class Tp, bool First = false>
struct TestTypes {
  typedef Tp* Type;
  typedef Tp const* CType;
  typedef Tp volatile* VType;
  typedef Tp const volatile* CVType;
};

// Special case for cv-qualifying a pointer-to-member without adding an extra
// pointer to it.
template <class Member, class Class>
struct TestTypes<Member Class::*, true> {
  typedef Member (Class::*Type);
  typedef const Member (Class::*CType);
  typedef volatile Member (Class::*VType);
  typedef const volatile Member (Class::*CVType);
};

template <class Throw, class Catch, int level, bool first = false>
struct generate_tests_imp {
  typedef TestTypes<Throw, first> ThrowTypes;
  typedef TestTypes<Catch, first> CatchTypes;
  void operator()() {
      typedef typename ThrowTypes::Type Type;
      typedef typename ThrowTypes::CType CType;
      typedef typename ThrowTypes::VType VType;
      typedef typename ThrowTypes::CVType CVType;

      run_catch_tests<Type>();
      run_catch_tests<CType>();
      run_catch_tests<VType>();
      run_catch_tests<CVType>();
  }

  template <class ThrowTp>
  void run_catch_tests() {
      typedef typename CatchTypes::Type Type;
      typedef typename CatchTypes::CType CType;
      typedef typename CatchTypes::VType VType;
      typedef typename CatchTypes::CVType CVType;

      catch_pointer_test<ThrowTp, Type>();
      catch_pointer_test<ThrowTp, CType>();
      catch_pointer_test<ThrowTp, VType>();
      catch_pointer_test<ThrowTp, CVType>();

      generate_tests_imp<ThrowTp, Type, level-1>()();
      generate_tests_imp<ThrowTp, CType, level-1>()();
      generate_tests_imp<ThrowTp, VType, level-1>()();
      generate_tests_imp<ThrowTp, CVType, level-1>()();
  }
};

template <class Throw, class Catch, bool first>
struct generate_tests_imp<Throw, Catch, 0, first> {
  void operator()() {
      catch_pointer_test<Throw, Catch>();
  }
};

template <class Throw, class Catch, int level>
struct generate_tests : generate_tests_imp<Throw, Catch, level, true> {};

int main()
{
  generate_tests<int, int, 3>()();
  generate_tests<Base, Derived, 2>()();
  generate_tests<Derived, Base, 2>()();
  generate_tests<int, void, 2>()();
  generate_tests<void, int, 2>()();

  generate_tests<int A::*, int A::*, 3>()();
  generate_tests<int A::*, void, 2>()();
  generate_tests<void, int A::*, 2>()();
}