blob: 784637621697ff5400901c2dbab7d336c9c969b9 [file] [log] [blame]
//===--------------------- 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);
}
}