This was put in to get libc++ building without libcxxabi. We now have macros that show that we are building against libcxxabi so use that instead. This guards against existing but broken cxxabi.h headers on the system. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@250507 91177308-0d34-0410-b5e6-96231b3b80d8
310 lines
8.2 KiB
C++
310 lines
8.2 KiB
C++
//===------------------------ exception.cpp -------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is dual licensed under the MIT and the University of Illinois Open
|
|
// Source Licenses. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "exception"
|
|
#include "new"
|
|
|
|
#if defined(__APPLE__) && !defined(LIBCXXRT)
|
|
#include <cxxabi.h>
|
|
|
|
using namespace __cxxabiv1;
|
|
#define HAVE_DEPENDENT_EH_ABI 1
|
|
#ifndef _LIBCPPABI_VERSION
|
|
using namespace __cxxabiapple;
|
|
// On Darwin, there are two STL shared libraries and a lower level ABI
|
|
// shared library. The globals holding the current terminate handler and
|
|
// current unexpected handler are in the ABI library.
|
|
#define __terminate_handler __cxxabiapple::__cxa_terminate_handler
|
|
#define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
|
|
#endif // _LIBCPPABI_VERSION
|
|
#elif defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI)
|
|
#include <cxxabi.h>
|
|
using namespace __cxxabiv1;
|
|
#if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
|
|
#define HAVE_DEPENDENT_EH_ABI 1
|
|
#endif
|
|
#elif !defined(__GLIBCXX__) // defined(LIBCXX_BUILDING_LIBCXXABI)
|
|
static std::terminate_handler __terminate_handler;
|
|
static std::unexpected_handler __unexpected_handler;
|
|
#endif // defined(LIBCXX_BUILDING_LIBCXXABI)
|
|
|
|
namespace std
|
|
{
|
|
|
|
#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
|
|
|
|
// libcxxrt provides implementations of these functions itself.
|
|
unexpected_handler
|
|
set_unexpected(unexpected_handler func) _NOEXCEPT
|
|
{
|
|
return __sync_lock_test_and_set(&__unexpected_handler, func);
|
|
}
|
|
|
|
unexpected_handler
|
|
get_unexpected() _NOEXCEPT
|
|
{
|
|
return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
|
|
}
|
|
|
|
_LIBCPP_NORETURN
|
|
void
|
|
unexpected()
|
|
{
|
|
(*get_unexpected())();
|
|
// unexpected handler should not return
|
|
terminate();
|
|
}
|
|
|
|
terminate_handler
|
|
set_terminate(terminate_handler func) _NOEXCEPT
|
|
{
|
|
return __sync_lock_test_and_set(&__terminate_handler, func);
|
|
}
|
|
|
|
terminate_handler
|
|
get_terminate() _NOEXCEPT
|
|
{
|
|
return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
|
|
}
|
|
|
|
#ifndef __EMSCRIPTEN__ // We provide this in JS
|
|
_LIBCPP_NORETURN
|
|
void
|
|
terminate() _NOEXCEPT
|
|
{
|
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
try
|
|
{
|
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
|
(*get_terminate())();
|
|
// handler should not return
|
|
fprintf(stderr, "terminate_handler unexpectedly returned\n");
|
|
::abort();
|
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
}
|
|
catch (...)
|
|
{
|
|
// handler should not throw exception
|
|
fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
|
|
::abort();
|
|
}
|
|
#endif // _LIBCPP_NO_EXCEPTIONS
|
|
}
|
|
#endif // !__EMSCRIPTEN__
|
|
#endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
|
|
|
|
#if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__)
|
|
bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
|
|
|
|
int uncaught_exceptions() _NOEXCEPT
|
|
{
|
|
#if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
|
|
// on Darwin, there is a helper function so __cxa_get_globals is private
|
|
# if _LIBCPPABI_VERSION > 1101
|
|
return __cxa_uncaught_exceptions();
|
|
# else
|
|
return __cxa_uncaught_exception() ? 1 : 0;
|
|
# endif
|
|
#else // __APPLE__
|
|
# if defined(_MSC_VER) && ! defined(__clang__)
|
|
_LIBCPP_WARNING("uncaught_exceptions not yet implemented")
|
|
# else
|
|
# warning uncaught_exception not yet implemented
|
|
# endif
|
|
fprintf(stderr, "uncaught_exceptions not yet implemented\n");
|
|
::abort();
|
|
#endif // __APPLE__
|
|
}
|
|
|
|
|
|
#ifndef _LIBCPPABI_VERSION
|
|
|
|
exception::~exception() _NOEXCEPT
|
|
{
|
|
}
|
|
|
|
const char* exception::what() const _NOEXCEPT
|
|
{
|
|
return "std::exception";
|
|
}
|
|
|
|
#endif // _LIBCPPABI_VERSION
|
|
#endif //LIBCXXRT
|
|
#if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
|
|
|
|
bad_exception::~bad_exception() _NOEXCEPT
|
|
{
|
|
}
|
|
|
|
const char* bad_exception::what() const _NOEXCEPT
|
|
{
|
|
return "std::bad_exception";
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(__GLIBCXX__)
|
|
|
|
// libsupc++ does not implement the dependent EH ABI and the functionality
|
|
// it uses to implement std::exception_ptr (which it declares as an alias of
|
|
// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
|
|
// we have little choice but to hijack std::__exception_ptr::exception_ptr's
|
|
// (which fortunately has the same layout as our std::exception_ptr) copy
|
|
// constructor, assignment operator and destructor (which are part of its
|
|
// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
|
|
// function.
|
|
|
|
namespace __exception_ptr
|
|
{
|
|
|
|
struct exception_ptr
|
|
{
|
|
void* __ptr_;
|
|
|
|
exception_ptr(const exception_ptr&) _NOEXCEPT;
|
|
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
|
|
~exception_ptr() _NOEXCEPT;
|
|
};
|
|
|
|
}
|
|
|
|
_LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
|
|
|
|
#endif
|
|
|
|
exception_ptr::~exception_ptr() _NOEXCEPT
|
|
{
|
|
#if HAVE_DEPENDENT_EH_ABI
|
|
__cxa_decrement_exception_refcount(__ptr_);
|
|
#elif defined(__GLIBCXX__)
|
|
reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
|
|
#else
|
|
# if defined(_MSC_VER) && ! defined(__clang__)
|
|
_LIBCPP_WARNING("exception_ptr not yet implemented")
|
|
# else
|
|
# warning exception_ptr not yet implemented
|
|
# endif
|
|
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
::abort();
|
|
#endif
|
|
}
|
|
|
|
exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
|
|
: __ptr_(other.__ptr_)
|
|
{
|
|
#if HAVE_DEPENDENT_EH_ABI
|
|
__cxa_increment_exception_refcount(__ptr_);
|
|
#elif defined(__GLIBCXX__)
|
|
new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
|
|
reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
|
|
#else
|
|
# if defined(_MSC_VER) && ! defined(__clang__)
|
|
_LIBCPP_WARNING("exception_ptr not yet implemented")
|
|
# else
|
|
# warning exception_ptr not yet implemented
|
|
# endif
|
|
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
::abort();
|
|
#endif
|
|
}
|
|
|
|
exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
|
|
{
|
|
#if HAVE_DEPENDENT_EH_ABI
|
|
if (__ptr_ != other.__ptr_)
|
|
{
|
|
__cxa_increment_exception_refcount(other.__ptr_);
|
|
__cxa_decrement_exception_refcount(__ptr_);
|
|
__ptr_ = other.__ptr_;
|
|
}
|
|
return *this;
|
|
#elif defined(__GLIBCXX__)
|
|
*reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
|
|
reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
|
|
return *this;
|
|
#else
|
|
# if defined(_MSC_VER) && ! defined(__clang__)
|
|
_LIBCPP_WARNING("exception_ptr not yet implemented")
|
|
# else
|
|
# warning exception_ptr not yet implemented
|
|
# endif
|
|
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
::abort();
|
|
#endif
|
|
}
|
|
|
|
nested_exception::nested_exception() _NOEXCEPT
|
|
: __ptr_(current_exception())
|
|
{
|
|
}
|
|
|
|
#if !defined(__GLIBCXX__)
|
|
|
|
nested_exception::~nested_exception() _NOEXCEPT
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
_LIBCPP_NORETURN
|
|
void
|
|
nested_exception::rethrow_nested() const
|
|
{
|
|
if (__ptr_ == nullptr)
|
|
terminate();
|
|
rethrow_exception(__ptr_);
|
|
}
|
|
|
|
#if !defined(__GLIBCXX__)
|
|
|
|
exception_ptr current_exception() _NOEXCEPT
|
|
{
|
|
#if HAVE_DEPENDENT_EH_ABI
|
|
// be nicer if there was a constructor that took a ptr, then
|
|
// this whole function would be just:
|
|
// return exception_ptr(__cxa_current_primary_exception());
|
|
exception_ptr ptr;
|
|
ptr.__ptr_ = __cxa_current_primary_exception();
|
|
return ptr;
|
|
#else
|
|
# if defined(_MSC_VER) && ! defined(__clang__)
|
|
_LIBCPP_WARNING( "exception_ptr not yet implemented" )
|
|
# else
|
|
# warning exception_ptr not yet implemented
|
|
# endif
|
|
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
::abort();
|
|
#endif
|
|
}
|
|
|
|
#endif // !__GLIBCXX__
|
|
|
|
_LIBCPP_NORETURN
|
|
void rethrow_exception(exception_ptr p)
|
|
{
|
|
#if HAVE_DEPENDENT_EH_ABI
|
|
__cxa_rethrow_primary_exception(p.__ptr_);
|
|
// if p.__ptr_ is NULL, above returns so we terminate
|
|
terminate();
|
|
#elif defined(__GLIBCXX__)
|
|
rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
|
|
#else
|
|
# if defined(_MSC_VER) && ! defined(__clang__)
|
|
_LIBCPP_WARNING("exception_ptr not yet implemented")
|
|
# else
|
|
# warning exception_ptr not yet implemented
|
|
# endif
|
|
fprintf(stderr, "exception_ptr not yet implemented\n");
|
|
::abort();
|
|
#endif
|
|
}
|
|
} // std
|