1 //===---------------------- catch_class_03.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.
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_;
BB38     explicit B(int id) : id_(id) {count++;}
BB39     B(const B& a) : id_(a.id_) {count++;}
~BB40     ~B() {count--;}
41 };
42 
43 int B::count = 0;
44 
45 struct C1
46     : B
47 {
48     static int count;
49     int id_;
C1C150     explicit C1(int id) : B(id-2), id_(id) {count++;}
C1C151     C1(const C1& a) : B(a.id_-2), id_(a.id_) {count++;}
~C1C152     ~C1() {count--;}
53 };
54 
55 int C1::count = 0;
56 
57 struct C2
58     : B
59 {
60     static int count;
61     int id_;
C2C262     explicit C2(int id) : B(id-2), id_(id) {count++;}
C2C263     C2(const C2& a) : B(a.id_-2), id_(a.id_) {count++;}
~C2C264     ~C2() {count--;}
65 };
66 
67 int C2::count = 0;
68 
69 struct A
70     : C1, C2
71 {
72     static int count;
73     int id_;
AA74     explicit A(int id) : C1(id-1), C2(id-2), id_(id) {count++;}
AA75     A(const A& a) : C1(a.id_-1), C2(a.id_-2), id_(a.id_) {count++;}
~AA76     ~A() {count--;}
77 };
78 
79 int A::count = 0;
80 
f1()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 == 2);
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&>(static_cast<C1&>(a)).id_ == 2);
97     assert(static_cast<B&>(static_cast<C2&>(a)).id_ == 1);
98     throw a;
99     assert(false);
100 }
101 
f2()102 void f2()
103 {
104     try
105     {
106         assert(A::count == 0);
107         assert(C1::count == 0);
108         assert(C2::count == 0);
109         assert(B::count == 0);
110         f1();
111         assert(false);
112     }
113     catch (const A& a)  // can catch A
114     {
115         assert(a.id_ == 5);
116         assert(static_cast<const C1&>(a).id_ == 4);
117         assert(static_cast<const C2&>(a).id_ == 3);
118         assert(static_cast<const B&>(static_cast<const C1&>(a)).id_ == 2);
119         assert(static_cast<const B&>(static_cast<const C2&>(a)).id_ == 1);
120         throw;
121     }
122     catch (const C1&)
123     {
124         assert(false);
125     }
126     catch (const C2&)
127     {
128         assert(false);
129     }
130     catch (const B&)
131     {
132         assert(false);
133     }
134 }
135 
f3()136 void f3()
137 {
138     try
139     {
140         assert(A::count == 0);
141         assert(C1::count == 0);
142         assert(C2::count == 0);
143         assert(B::count == 0);
144         f2();
145         assert(false);
146     }
147     catch (const B& a)  // can not catch B (ambiguous base)
148     {
149         assert(false);
150     }
151     catch (const C1& c1)  // can catch C1
152     {
153         assert(c1.id_ == 4);
154         assert(static_cast<const B&>(c1).id_ == 2);
155         throw;
156     }
157     catch (const C2&)
158     {
159         assert(false);
160     }
161 }
162 
f4()163 void f4()
164 {
165     try
166     {
167         assert(A::count == 0);
168         assert(C1::count == 0);
169         assert(C2::count == 0);
170         assert(B::count == 0);
171         f3();
172         assert(false);
173     }
174     catch (const B& a)  // can not catch B (ambiguous base)
175     {
176         assert(false);
177     }
178     catch (const C2& c2)  // can catch C2
179     {
180         assert(c2.id_ == 3);
181         assert(static_cast<const B&>(c2).id_ == 1);
182         throw;
183     }
184     catch (const C1&)
185     {
186         assert(false);
187     }
188 }
189 
main(int,char **)190 int main(int, char**)
191 {
192     try
193     {
194         f4();
195         assert(false);
196     }
197     catch (...)
198     {
199     }
200     assert(A::count == 0);
201     assert(C1::count == 0);
202     assert(C2::count == 0);
203     assert(B::count == 0);
204 
205     return 0;
206 }
207