1 //===--------------------- inherited_exception.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 // This test case checks specifically the cases under C++ ABI 15.3.1, and 15.3.2
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 // Clang emits  warnings about exceptions of type 'Child' being caught by
30 // an earlier handler of type 'Base'. Congrats clang, you've just
31 // diagnosed the behavior under test.
32 #if defined(__clang__)
33 #pragma clang diagnostic ignored "-Wexceptions"
34 #endif
35 
36 #include <assert.h>
37 
38 struct Base {
39   int b1;
40 };
41 
42 struct Base2 {
43   int b2;
44 };
45 
46 struct Child : public Base, public Base2 {
47   int c;
48 };
49 
50 void f1() {
51   Child child;
52   child.b1 = 10;
53   child.b2 = 11;
54   child.c = 12;
55   throw child;
56 }
57 
58 void f2() {
59   Child child;
60   child.b1 = 10;
61   child.b2 = 11;
62   child.c = 12;
63   throw static_cast<Base2&>(child);
64 }
65 
66 void f3() {
67   static Child child;
68   child.b1 = 10;
69   child.b2 = 11;
70   child.c = 12;
71   throw static_cast<Base2*>(&child);
72 }
73 
74 int main()
75 {
76     try
77     {
78         f1();
79         assert(false);
80     }
81     catch (const Child& c)
82     {
83         assert(true);
84     }
85     catch (const Base& b)
86     {
87         assert(false);
88     }
89     catch (...)
90     {
91         assert(false);
92     }
93 
94     try
95     {
96         f1();
97         assert(false);
98     }
99     catch (const Base& c)
100     {
101         assert(true);
102     }
103     catch (const Child& b)
104     {
105         assert(false);
106     }
107     catch (...)
108     {
109         assert(false);
110     }
111 
112     try
113     {
114         f1();
115         assert(false);
116     }
117     catch (const Base2& c)
118     {
119         assert(true);
120     }
121     catch (const Child& b)
122     {
123         assert(false);
124     }
125     catch (...)
126     {
127         assert(false);
128     }
129 
130     try
131     {
132         f2();
133         assert(false);
134     }
135     catch (const Child& c)
136     {
137         assert(false);
138     }
139     catch (const Base& b)
140     {
141         assert(false);
142     }
143     catch (const Base2& b)
144     {
145         assert(true);
146     }
147     catch (...)
148     {
149         assert(false);
150     }
151 
152     try
153     {
154         f3();
155         assert(false);
156     }
157     catch (const Base* c)
158     {
159         assert(false);
160     }
161     catch (const Child* b)
162     {
163         assert(false);
164     }
165     catch (const Base2* c)
166     {
167         assert(true);
168     }
169     catch (...)
170     {
171         assert(false);
172     }
173 }
174