| //===--------------------- 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: 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. | |
| 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); | |
| } | |
| } | |