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