1 //===---------------------- catch_class_04.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 /*
10     This test checks that adjustedPtr is correct as there exist offsets in this
11     object for the various subobjects, all of which have a unique id_ to
12     check against.  It also checks that virtual bases work properly
13 */
14 
15 // UNSUPPORTED: no-exceptions
16 
17 // FIXME: GCC doesn't allow turning off the warning for exceptions being caught
18 //        by earlier handlers, which this test is exercising. We have to disable
19 //        warnings altogether to remove the error.
20 //        See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97675.
21 // ADDITIONAL_COMPILE_FLAGS: -Wno-error
22 
23 #include <exception>
24 #include <stdlib.h>
25 #include <assert.h>
26 
27 // Clang emits  warnings about exceptions of type 'Child' being caught by
28 // an earlier handler of type 'Base'. Congrats clang, you've just
29 // diagnosed the behavior under test.
30 #if defined(__clang__)
31 #pragma clang diagnostic ignored "-Wexceptions"
32 #endif
33 
34 struct B
35 {
36     static int count;
37     int id_;
38     explicit B(int id) : id_(id) {count++;}
39     B(const B& a) : id_(a.id_) {count++;}
40     ~B() {count--;}
41 };
42 
43 int B::count = 0;
44 
45 struct C1
46     : virtual B
47 {
48     static int count;
49     int id_;
50     explicit C1(int id) : B(id-2), id_(id) {count++;}
51     C1(const C1& a) : B(a.id_-2), id_(a.id_) {count++;}
52     ~C1() {count--;}
53 };
54 
55 int C1::count = 0;
56 
57 struct C2
58     : virtual private B
59 {
60     static int count;
61     int id_;
62     explicit C2(int id) : B(id-2), id_(id) {count++;}
63     C2(const C2& a) : B(a.id_-2), id_(a.id_) {count++;}
64     ~C2() {count--;}
65 };
66 
67 int C2::count = 0;
68 
69 struct A
70     : C1, C2
71 {
72     static int count;
73     int id_;
74     explicit A(int id) : B(id+3), C1(id-1), C2(id-2), id_(id) {count++;}
75     A(const A& a) :  B(a.id_+3), C1(a.id_-1), C2(a.id_-2), id_(a.id_) {count++;}
76     ~A() {count--;}
77 };
78 
79 int A::count = 0;
80 
81 void f1()
82 {
83     assert(A::count == 0);
84     assert(C1::count == 0);
85     assert(C2::count == 0);
86     assert(B::count == 0);
87     A a(5);
88     assert(A::count == 1);
89     assert(C1::count == 1);
90     assert(C2::count == 1);
91     assert(B::count == 1);
92 
93     assert(a.id_ == 5);
94     assert(static_cast<C1&>(a).id_ == 4);
95     assert(static_cast<C2&>(a).id_ == 3);
96     assert(static_cast<B&>(a).id_ == 8);
97     throw a;
98     assert(false);
99 }
100 
101 void f2()
102 {
103     try
104     {
105         assert(A::count == 0);
106         assert(C1::count == 0);
107         assert(C2::count == 0);
108         assert(B::count == 0);
109         f1();
110         assert(false);
111     }
112     catch (const A& a)  // can catch A
113     {
114         assert(a.id_ == 5);
115         assert(static_cast<const C1&>(a).id_ == 4);
116         assert(static_cast<const C2&>(a).id_ == 3);
117         assert(static_cast<const B&>(a).id_ == 8);
118         throw;
119     }
120     catch (const C1&)
121     {
122         assert(false);
123     }
124     catch (const C2&)
125     {
126         assert(false);
127     }
128     catch (const B&)
129     {
130         assert(false);
131     }
132 }
133 
134 void f3()
135 {
136     try
137     {
138         assert(A::count == 0);
139         assert(C1::count == 0);
140         assert(C2::count == 0);
141         assert(B::count == 0);
142         f2();
143         assert(false);
144     }
145     catch (const B& a)  // can catch B
146     {
147         assert(static_cast<const B&>(a).id_ == 8);
148         throw;
149     }
150     catch (const C1& c1)
151     {
152         assert(false);
153     }
154     catch (const C2&)
155     {
156         assert(false);
157     }
158 }
159 
160 void f4()
161 {
162     try
163     {
164         assert(A::count == 0);
165         assert(C1::count == 0);
166         assert(C2::count == 0);
167         assert(B::count == 0);
168         f3();
169         assert(false);
170     }
171     catch (const C2& c2)  // can catch C2
172     {
173         assert(c2.id_ == 3);
174         throw;
175     }
176     catch (const B& a)  // can not catch B (ambiguous base)
177     {
178         assert(false);
179     }
180     catch (const C1&)
181     {
182         assert(false);
183     }
184 }
185 
186 void f5()
187 {
188     try
189     {
190         assert(A::count == 0);
191         assert(C1::count == 0);
192         assert(C2::count == 0);
193         assert(B::count == 0);
194         f4();
195         assert(false);
196     }
197     catch (const C1& c1)  // can catch C1
198     {
199         assert(c1.id_ == 4);
200         assert(static_cast<const B&>(c1).id_ == 8);
201         throw;
202     }
203     catch (const B& a)
204     {
205         assert(false);
206     }
207     catch (const C2&)
208     {
209         assert(false);
210     }
211 }
212 
213 int main(int, char**)
214 {
215     try
216     {
217         f5();
218         assert(false);
219     }
220     catch (...)
221     {
222     }
223     assert(A::count == 0);
224     assert(C1::count == 0);
225     assert(C2::count == 0);
226     assert(B::count == 0);
227 
228     return 0;
229 }
230