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 // This test case checks specifically the cases under bullet 3.3:
10 //
11 // C++ ABI 15.3:
12 // A handler is a match for an exception object of type E if
13 // * The handler is of type cv T or cv T& and E and T are the same type
14 // (ignoring the top-level cv-qualifiers), or
15 // * the handler is of type cv T or cv T& and T is an unambiguous base
16 // class of E, or
17 // > * the handler is of type cv1 T* cv2 and E is a pointer type that can <
18 // > be converted to the type of the handler by either or both of <
19 // > o a standard pointer conversion (4.10 [conv.ptr]) not involving <
20 // > conversions to private or protected or ambiguous classes <
21 // > o a qualification conversion <
22 // * the handler is a pointer or pointer to member type and E is
23 // std::nullptr_t
24 //
25 //===----------------------------------------------------------------------===//
26
27 // UNSUPPORTED: no-exceptions
28
29 // This test requires the fix to https://github.com/llvm/llvm-project/issues/64953,
30 // which landed in d5f84e6 and is in the libc++abi built library.
31 // XFAIL: using-built-library-before-llvm-18
32
33 #include <exception>
34 #include <stdlib.h>
35 #include <assert.h>
36 #include <stdio.h>
37
38 struct Base {
39 int b;
40 };
41 struct Base2 {
42 int b;
43 };
44 struct Derived1 : Base {
45 int b;
46 };
47 struct Derived2 : Base {
48 int b;
49 };
50 struct Derived3 : Base2 {
51 int b;
52 };
53 struct Private : private Base {
54 int b;
55 };
56 struct Protected : protected Base {
57 int b;
58 };
59 struct Virtual1 : virtual Base {
60 int b;
61 };
62 struct Virtual2 : virtual Base {
63 int b;
64 };
65
66 struct Ambiguous1 : Derived1, Derived2 {
67 int b;
68 };
69 struct Ambiguous2 : Derived1, Private {
70 int b;
71 };
72 struct Ambiguous3 : Derived1, Protected {
73 int b;
74 };
75
76 struct NoPublic1 : Private, Base2 {
77 int b;
78 };
79 struct NoPublic2 : Protected, Base2 {
80 int b;
81 };
82
83 struct Catchable1 : Derived3, Derived1 {
84 int b;
85 };
86 struct Catchable2 : Virtual1, Virtual2 {
87 int b;
88 };
89 struct Catchable3 : virtual Base, Virtual2 {
90 int b;
91 };
92
93 // Check that, when we have a null pointer-to-object that we catch a nullptr.
94 template <typename T // Handler type
95 ,
96 typename E // Thrown exception type
97 >
assert_catches()98 void assert_catches() {
99 try {
100 throw static_cast<E>(0);
101 printf("%s\n", __PRETTY_FUNCTION__);
102 assert(false && "Statements after throw must be unreachable");
103 } catch (T t) {
104 assert(t == nullptr);
105 return;
106 } catch (...) {
107 printf("%s\n", __PRETTY_FUNCTION__);
108 assert(false && "Should not have entered catch-all");
109 }
110
111 printf("%s\n", __PRETTY_FUNCTION__);
112 assert(false && "The catch should have returned");
113 }
114
115 template <typename T // Handler type
116 ,
117 typename E // Thrown exception type
118 >
assert_cannot_catch()119 void assert_cannot_catch() {
120 try {
121 throw static_cast<E>(0);
122 printf("%s\n", __PRETTY_FUNCTION__);
123 assert(false && "Statements after throw must be unreachable");
124 } catch (T t) {
125 printf("%s\n", __PRETTY_FUNCTION__);
126 assert(false && "Should not have entered the catch");
127 } catch (...) {
128 assert(true);
129 return;
130 }
131
132 printf("%s\n", __PRETTY_FUNCTION__);
133 assert(false && "The catch-all should have returned");
134 }
135
136 // Check that when we have a pointer-to-actual-object we, in fact, get the
137 // adjusted pointer to the base class.
138 template <typename T // Handler type
139 ,
140 typename O // Object type
141 >
assert_catches_bp()142 void assert_catches_bp() {
143 O* o = new (O);
144 try {
145 throw o;
146 printf("%s\n", __PRETTY_FUNCTION__);
147 assert(false && "Statements after throw must be unreachable");
148 } catch (T t) {
149 assert(t == static_cast<T>(o));
150 //__builtin_printf("o = %p t = %p\n", o, t);
151 delete o;
152 return;
153 } catch (...) {
154 printf("%s\n", __PRETTY_FUNCTION__);
155 assert(false && "Should not have entered catch-all");
156 }
157
158 printf("%s\n", __PRETTY_FUNCTION__);
159 assert(false && "The catch should have returned");
160 }
161
f1()162 void f1() {
163 assert_catches<Base*, Catchable1*>();
164 assert_catches<Base*, Catchable2*>();
165 assert_catches<Base*, Catchable3*>();
166 }
167
f2()168 void f2() {
169 assert_cannot_catch<Base*, Ambiguous1*>();
170 assert_cannot_catch<Base*, Ambiguous2*>();
171 assert_cannot_catch<Base*, Ambiguous3*>();
172 assert_cannot_catch<Base*, NoPublic1*>();
173 assert_cannot_catch<Base*, NoPublic2*>();
174 }
175
f3()176 void f3() {
177 assert_catches_bp<Base*, Catchable1>();
178 assert_catches_bp<Base*, Catchable2>();
179 assert_catches_bp<Base*, Catchable3>();
180 }
181
main(int,char **)182 int main(int, char**) {
183 f1();
184 f2();
185 f3();
186 return 0;
187 }
188