| //===--------------------- inherited_exception.cpp ------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This test case checks specifically the cases under C++ ABI 15.3.1, and 15.3.2 |
| // |
| // C++ ABI 15.3: |
| // A handler is a match for an exception object of type E if |
| // / * The handler is of type cv T or cv T& and E and T are the same type \ |
| // | (ignoring the top-level cv-qualifiers), or | |
| // | * the handler is of type cv T or cv T& and T is an unambiguous base | |
| // \ class of E, or / |
| // * the handler is of type cv1 T* cv2 and E is a pointer type that can |
| // be converted to the type of the handler by either or both of |
| // o a standard pointer conversion (4.10 [conv.ptr]) not involving |
| // conversions to private or protected or ambiguous classes |
| // o a qualification conversion |
| // * the handler is a pointer or pointer to member type and E is |
| // std::nullptr_t |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // UNSUPPORTED: libcxxabi-no-exceptions |
| |
| // Clang emits warnings about exceptions of type 'Child' being caught by |
| // an earlier handler of type 'Base'. Congrats clang, you've just |
| // diagnosed the behavior under test. |
| #if defined(__clang__) |
| #pragma clang diagnostic ignored "-Wexceptions" |
| #endif |
| |
| #include <assert.h> |
| |
| struct Base { |
| int b1; |
| }; |
| |
| struct Base2 { |
| int b2; |
| }; |
| |
| struct Child : public Base, public Base2 { |
| int c; |
| }; |
| |
| void f1() { |
| Child child; |
| child.b1 = 10; |
| child.b2 = 11; |
| child.c = 12; |
| throw child; |
| } |
| |
| void f2() { |
| Child child; |
| child.b1 = 10; |
| child.b2 = 11; |
| child.c = 12; |
| throw static_cast<Base2&>(child); |
| } |
| |
| void f3() { |
| static Child child; |
| child.b1 = 10; |
| child.b2 = 11; |
| child.c = 12; |
| throw static_cast<Base2*>(&child); |
| } |
| |
| int main() |
| { |
| try |
| { |
| f1(); |
| assert(false); |
| } |
| catch (const Child& c) |
| { |
| assert(true); |
| } |
| catch (const Base& b) |
| { |
| assert(false); |
| } |
| catch (...) |
| { |
| assert(false); |
| } |
| |
| try |
| { |
| f1(); |
| assert(false); |
| } |
| catch (const Base& c) |
| { |
| assert(true); |
| } |
| catch (const Child& b) |
| { |
| assert(false); |
| } |
| catch (...) |
| { |
| assert(false); |
| } |
| |
| try |
| { |
| f1(); |
| assert(false); |
| } |
| catch (const Base2& c) |
| { |
| assert(true); |
| } |
| catch (const Child& b) |
| { |
| assert(false); |
| } |
| catch (...) |
| { |
| assert(false); |
| } |
| |
| try |
| { |
| f2(); |
| assert(false); |
| } |
| catch (const Child& c) |
| { |
| assert(false); |
| } |
| catch (const Base& b) |
| { |
| assert(false); |
| } |
| catch (const Base2& b) |
| { |
| assert(true); |
| } |
| catch (...) |
| { |
| assert(false); |
| } |
| |
| try |
| { |
| f3(); |
| assert(false); |
| } |
| catch (const Base* c) |
| { |
| assert(false); |
| } |
| catch (const Child* b) |
| { |
| assert(false); |
| } |
| catch (const Base2* c) |
| { |
| assert(true); |
| } |
| catch (...) |
| { |
| assert(false); |
| } |
| } |