You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
libcxxrt/test/test_exception.cc

327 lines
5.3 KiB
C++

#include "test.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <exception>
#define fprintf(...)
void log(void* ignored)
{
//printf("Cleanup called on %s\n", *(char**)ignored);
}
#define CLEANUP\
__attribute__((cleanup(log))) __attribute__((unused))\
const char *f = __func__;
/**
* Simple struct to test throwing.
*/
struct foo
{
int i;
};
struct bar : foo
{
float bar;
};
/**
* Non-pod type to test throwing
*/
class non_pod {
public:
non_pod(int i): x(i) {}
int x;
};
static int cleanup_count;
/**
* Simple structure declared with a destructor. Destroying this object will
* increment cleanup count. The destructor should be called automatically if
* an instance of cl is allocated with automatic storage.
*/
struct cl
{
int i;
~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
};
/**
* Test that one cl was destroyed when running the argument.
*/
#define TEST_CLEANUP(x) do {\
int cleanups = cleanup_count;\
{ x; }\
TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
} while(0)
int inner(int i)
{
CLEANUP
switch (i)
{
case 0: throw (int)1.0;
case 1: throw (float)1.0;
case 2: fprintf(stderr, "Throwing int64_t\n");throw (int64_t)1;
case 3: { foo f = {2} ; throw f; }
case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
case 5: throw non_pod(3);
}
return -1;
}
int outer(int i) throw(float, int, foo, non_pod)
{
//CLEANUP
inner(i);
return 1;
}
static void test_const(void)
{
int a = 1;
try
{
throw a;
}
catch (const int b)
{
TEST(a == b, "Caught int as const int");
}
catch(...)
{
TEST(0, "Failed to catch int as const int");
}
try
{
throw &a;
}
catch (const int *b)
{
TEST(&a == b, "Caught int* as const int*");
}
catch(...)
{
TEST(0, "Failed to catch int* as const int*");
}
}
static void test_catch(int s)
{
cl c;
c.i = 12;
fprintf(stderr, "Entering try\n");
try
{
outer(s);
}
catch(int i)
{
fprintf(stderr, "Caught int %d in test %d\n", i, s);
TEST((s == 0 && i == 1) || (s == 2 && i == 0), "Caught int");
return;
}
catch (float f)
{
fprintf(stderr, "Caught float %f!\n", f);
TEST(s == 1 && f == 1, "Caught float");
return;
}
catch (foo f)
{
fprintf(stderr, "Caught struct {%d}!\n", f.i);
TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
return;
}
catch (non_pod np) {
fprintf(stderr, "Caught non_pod {%d}!\n", np.x);
TEST(s == 5 && np.x == 3, "Caught non_pod");
return;
}
//abort();
TEST(0, "Unreachable line reached");
}
void test_nested1(void)
{
CLEANUP;
cl c;
c.i = 123;
try
{
outer(0);
}
catch (int a)
{
try
{
TEST(a == 1, "Caught int");
outer(1);
}
catch (float f)
{
TEST(f == 1, "Caught float inside outer catch block");
throw;
}
}
}
void test_nested()
{
try
{
test_nested1();
}
catch (float f)
{
fprintf(stderr, "Caught re-thrown float\n");
TEST(f == 1, "Caught re-thrown float");
}
}
static int violations = 0;
static void throw_zero()
{
violations++;
fprintf(stderr, "Throwing 0\n");
throw 0;
}
struct uncaught_exception_checker
{
uncaught_exception_checker(bool uncaught) : m_uncaught(uncaught) {}
~uncaught_exception_checker() {
if (std::uncaught_exception())
TEST(m_uncaught, "At least one uncaught exception is in flight");
else
TEST(!m_uncaught, "No uncaught exceptions are in flight");
}
bool m_uncaught;
};
void test_uncaught_exception()
{
uncaught_exception_checker outer(false);
try {
uncaught_exception_checker inner(true);
throw 42;
}
catch (...) {}
}
struct uncaught_exceptions_checker
{
uncaught_exceptions_checker(int uncaught) : m_uncaught(uncaught) {}
~uncaught_exceptions_checker() {
char msg[128];
int uncaught = std::uncaught_exceptions();
snprintf(msg, sizeof msg, "%d uncaught exception%s in flight",
uncaught, uncaught == 1 ? " is" : "s are");
TEST(uncaught == m_uncaught, msg);
}
int m_uncaught;
};
class top {
public:
~top() {
try {
uncaught_exceptions_checker uec(4);
throw "top";
}
catch (...) {}
}
};
class middle {
public:
~middle() {
try {
top f;
uncaught_exceptions_checker uec(3);
throw "middle";
}
catch (...) {}
}
};
class bottom {
public:
~bottom() {
try {
middle f;
uncaught_exceptions_checker uec(2);
throw "bottom";
}
catch (...) {}
}
};
void test_uncaught_exceptions()
{
uncaught_exceptions_checker outer(0);
try {
bottom b;
uncaught_exceptions_checker inner(1);
throw "test";
}
catch (...) {}
}
extern "C" void __cxa_bad_cast();
void test_exceptions(void)
{
std::set_unexpected(throw_zero);
TEST_CLEANUP(test_catch(0));
TEST_CLEANUP(test_catch(1));
TEST_CLEANUP(test_catch(3));
TEST_CLEANUP(test_catch(4));
TEST_CLEANUP(test_catch(5));
TEST_CLEANUP(test_nested());
try{
test_catch(2);
TEST(violations == 1, "Exactly one exception spec violation");
}
catch (int64_t i) {
TEST(0, "Caught int64_t, but that violates an exception spec");
}
int a;
try {
throw &a;
}
catch (const int *b)
{
TEST(&a==b, "Caught const int from thrown int");
}
try {
throw &a;
}
catch (int *b)
{
TEST(&a==b, "Caught int from thrown int");
}
try
{
__cxa_bad_cast();
}
catch (std::exception b)
{
TEST(1, "Caught bad cast");
}
catch (...)
{
TEST(0, "Bad cast was not caught correctly");
}
test_const();
test_uncaught_exception();
test_uncaught_exceptions();
//printf("Test: %s\n",
}