exception.cpp revision 287679
11590Srgrimes//===------------------------ exception.cpp -------------------------------===//
21590Srgrimes//
31590Srgrimes//                     The LLVM Compiler Infrastructure
41590Srgrimes//
51590Srgrimes// This file is dual licensed under the MIT and the University of Illinois Open
61590Srgrimes// Source Licenses. See LICENSE.TXT for details.
71590Srgrimes//
81590Srgrimes//===----------------------------------------------------------------------===//
91590Srgrimes#include <stdlib.h>
101590Srgrimes#include <stdio.h>
111590Srgrimes
121590Srgrimes#include "exception"
131590Srgrimes#include "new"
141590Srgrimes
151590Srgrimes#ifndef __has_include
161590Srgrimes#define __has_include(inc) 0
171590Srgrimes#endif
181590Srgrimes
191590Srgrimes#if defined(__APPLE__) && !defined(LIBCXXRT)
201590Srgrimes  #include <cxxabi.h>
211590Srgrimes
221590Srgrimes  using namespace __cxxabiv1;
231590Srgrimes  #define HAVE_DEPENDENT_EH_ABI 1
241590Srgrimes  #ifndef _LIBCPPABI_VERSION
251590Srgrimes    using namespace __cxxabiapple;
261590Srgrimes    // On Darwin, there are two STL shared libraries and a lower level ABI
271590Srgrimes    // shared library.  The globals holding the current terminate handler and
281590Srgrimes    // current unexpected handler are in the ABI library.
291590Srgrimes    #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
301590Srgrimes    #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
311590Srgrimes  #endif  // _LIBCPPABI_VERSION
321590Srgrimes#elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
331590Srgrimes  #include <cxxabi.h>
341590Srgrimes  using namespace __cxxabiv1;
351590Srgrimes  #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
361590Srgrimes    #define HAVE_DEPENDENT_EH_ABI 1
3787712Smarkm  #endif
3887712Smarkm#elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>)
3987712Smarkm  static std::terminate_handler  __terminate_handler;
4087712Smarkm  static std::unexpected_handler __unexpected_handler;
411590Srgrimes#endif // __has_include(<cxxabi.h>)
4287712Smarkm
4328150Scharniernamespace std
441590Srgrimes{
451590Srgrimes
461590Srgrimes#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
471590Srgrimes
481590Srgrimes// libcxxrt provides implementations of these functions itself.
4987712Smarkmunexpected_handler
5087712Smarkmset_unexpected(unexpected_handler func) _NOEXCEPT
511590Srgrimes{
521590Srgrimes    return __sync_lock_test_and_set(&__unexpected_handler, func);
531590Srgrimes}
541590Srgrimes
5587712Smarkmunexpected_handler
5687712Smarkmget_unexpected() _NOEXCEPT
571590Srgrimes{
581590Srgrimes    return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
591590Srgrimes}
6082762Sache
611590Srgrimes_LIBCPP_NORETURN
621590Srgrimesvoid
631590Srgrimesunexpected()
641590Srgrimes{
651590Srgrimes    (*get_unexpected())();
661590Srgrimes    // unexpected handler should not return
671590Srgrimes    terminate();
681590Srgrimes}
691590Srgrimes
701590Srgrimesterminate_handler
711590Srgrimesset_terminate(terminate_handler func) _NOEXCEPT
721590Srgrimes{
731590Srgrimes    return __sync_lock_test_and_set(&__terminate_handler, func);
741590Srgrimes}
751590Srgrimes
761590Srgrimesterminate_handler
771590Srgrimesget_terminate() _NOEXCEPT
781590Srgrimes{
791590Srgrimes    return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
801590Srgrimes}
811590Srgrimes
821590Srgrimes#ifndef __EMSCRIPTEN__ // We provide this in JS
831590Srgrimes_LIBCPP_NORETURN
8482762Sachevoid
851590Srgrimesterminate() _NOEXCEPT
861590Srgrimes{
871590Srgrimes#ifndef _LIBCPP_NO_EXCEPTIONS
881590Srgrimes    try
891590Srgrimes    {
901590Srgrimes#endif  // _LIBCPP_NO_EXCEPTIONS
911590Srgrimes        (*get_terminate())();
921590Srgrimes        // handler should not return
931590Srgrimes        printf("terminate_handler unexpectedly returned\n");
941590Srgrimes        ::abort();
951590Srgrimes#ifndef _LIBCPP_NO_EXCEPTIONS
961590Srgrimes    }
971590Srgrimes    catch (...)
981590Srgrimes    {
991590Srgrimes        // handler should not throw exception
1001590Srgrimes        printf("terminate_handler unexpectedly threw an exception\n");
1011590Srgrimes        ::abort();
1021590Srgrimes    }
1031590Srgrimes#endif  // _LIBCPP_NO_EXCEPTIONS
1041590Srgrimes}
10587712Smarkm#endif // !__EMSCRIPTEN__
1061590Srgrimes#endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
1071590Srgrimes
1081590Srgrimes#if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__)
1091590Srgrimesbool uncaught_exception() _NOEXCEPT
1101590Srgrimes{
1111590Srgrimes#if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
1121590Srgrimes    // on Darwin, there is a helper function so __cxa_get_globals is private
1131590Srgrimes    return __cxa_uncaught_exception();
1141590Srgrimes#else  // __APPLE__
11569552Sasmodai#   if defined(_MSC_VER) && ! defined(__clang__)
11682762Sache        _LIBCPP_WARNING("uncaught_exception not yet implemented")
1171590Srgrimes#   else
1181590Srgrimes#       warning uncaught_exception not yet implemented
11974876Sdwmalone#   endif
12074876Sdwmalone    printf("uncaught_exception not yet implemented\n");
12174876Sdwmalone    ::abort();
1221590Srgrimes#endif  // __APPLE__
1231590Srgrimes}
1241590Srgrimes
1251590Srgrimes
12674876Sdwmalone#ifndef _LIBCPPABI_VERSION
12774876Sdwmalone
12874876Sdwmaloneexception::~exception() _NOEXCEPT
1291590Srgrimes{
13074876Sdwmalone}
13174876Sdwmalone
13274876Sdwmaloneconst char* exception::what() const _NOEXCEPT
13374876Sdwmalone{
13474876Sdwmalone  return "std::exception";
13574876Sdwmalone}
13674876Sdwmalone
13774876Sdwmalone#endif  // _LIBCPPABI_VERSION
13874876Sdwmalone#endif //LIBCXXRT
13974876Sdwmalone#if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
14074876Sdwmalone
14174876Sdwmalonebad_exception::~bad_exception() _NOEXCEPT
14274876Sdwmalone{
14374876Sdwmalone}
14474876Sdwmalone
14574876Sdwmaloneconst char* bad_exception::what() const _NOEXCEPT
14674876Sdwmalone{
14774876Sdwmalone  return "std::bad_exception";
14874876Sdwmalone}
14974876Sdwmalone
15074876Sdwmalone#endif
15174876Sdwmalone
15274876Sdwmalone#if defined(__GLIBCXX__)
1531590Srgrimes
15474876Sdwmalone// libsupc++ does not implement the dependent EH ABI and the functionality
15574876Sdwmalone// it uses to implement std::exception_ptr (which it declares as an alias of
15674876Sdwmalone// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
15774876Sdwmalone// we have little choice but to hijack std::__exception_ptr::exception_ptr's
15874876Sdwmalone// (which fortunately has the same layout as our std::exception_ptr) copy
15974876Sdwmalone// constructor, assignment operator and destructor (which are part of its
16074876Sdwmalone// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
1611590Srgrimes// function.
16274876Sdwmalone
16374876Sdwmalonenamespace __exception_ptr
16474876Sdwmalone{
16574876Sdwmalone
16674876Sdwmalonestruct exception_ptr
16774876Sdwmalone{
16874876Sdwmalone    void* __ptr_;
1691590Srgrimes
17074876Sdwmalone    exception_ptr(const exception_ptr&) _NOEXCEPT;
17174876Sdwmalone    exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
17217833Sadam    ~exception_ptr() _NOEXCEPT;
17374876Sdwmalone};
17474876Sdwmalone
17574876Sdwmalone}
17674876Sdwmalone
1771590Srgrimes_LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
1781590Srgrimes
1791590Srgrimes#endif
1801590Srgrimes
1811590Srgrimesexception_ptr::~exception_ptr() _NOEXCEPT
1821590Srgrimes{
1831590Srgrimes#if HAVE_DEPENDENT_EH_ABI
1841590Srgrimes    __cxa_decrement_exception_refcount(__ptr_);
1851590Srgrimes#elif defined(__GLIBCXX__)
1861590Srgrimes    reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
1871590Srgrimes#else
1881590Srgrimes#   if defined(_MSC_VER) && ! defined(__clang__)
1891590Srgrimes        _LIBCPP_WARNING("exception_ptr not yet implemented")
1901590Srgrimes#   else
1911590Srgrimes#       warning exception_ptr not yet implemented
1921590Srgrimes#   endif
1931590Srgrimes    printf("exception_ptr not yet implemented\n");
1941590Srgrimes    ::abort();
1951590Srgrimes#endif
1961590Srgrimes}
1971590Srgrimes
1981590Srgrimesexception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
1991590Srgrimes    : __ptr_(other.__ptr_)
20069552Sasmodai{
20169552Sasmodai#if HAVE_DEPENDENT_EH_ABI
20269552Sasmodai    __cxa_increment_exception_refcount(__ptr_);
2031590Srgrimes#elif defined(__GLIBCXX__)
2041590Srgrimes    new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
2051590Srgrimes        reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
2061590Srgrimes#else
2071590Srgrimes#   if defined(_MSC_VER) && ! defined(__clang__)
2081590Srgrimes        _LIBCPP_WARNING("exception_ptr not yet implemented")
2091590Srgrimes#   else
2101590Srgrimes#       warning exception_ptr not yet implemented
2111590Srgrimes#   endif
2121590Srgrimes    printf("exception_ptr not yet implemented\n");
2131590Srgrimes    ::abort();
2141590Srgrimes#endif
21517825Speter}
2161590Srgrimes
2171590Srgrimesexception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
2181590Srgrimes{
2191590Srgrimes#if HAVE_DEPENDENT_EH_ABI
2201590Srgrimes    if (__ptr_ != other.__ptr_)
2211590Srgrimes    {
2221590Srgrimes        __cxa_increment_exception_refcount(other.__ptr_);
2231590Srgrimes        __cxa_decrement_exception_refcount(__ptr_);
2241590Srgrimes        __ptr_ = other.__ptr_;
2251590Srgrimes    }
2261590Srgrimes    return *this;
2271590Srgrimes#elif defined(__GLIBCXX__)
2281590Srgrimes    *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
2291590Srgrimes        reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
2301590Srgrimes    return *this;
23117339Sadam#else
23217339Sadam#   if defined(_MSC_VER) && ! defined(__clang__)
23317339Sadam        _LIBCPP_WARNING("exception_ptr not yet implemented")
23417339Sadam#   else
23517339Sadam#       warning exception_ptr not yet implemented
2361590Srgrimes#   endif
2371590Srgrimes    printf("exception_ptr not yet implemented\n");
2381590Srgrimes    ::abort();
2391590Srgrimes#endif
2401590Srgrimes}
2411590Srgrimes
2421590Srgrimesnested_exception::nested_exception() _NOEXCEPT
2431590Srgrimes    : __ptr_(current_exception())
2441590Srgrimes{
2451590Srgrimes}
2461590Srgrimes
2471590Srgrimes#if !defined(__GLIBCXX__)
2481590Srgrimes
2491590Srgrimesnested_exception::~nested_exception() _NOEXCEPT
2501590Srgrimes{
2511590Srgrimes}
2521590Srgrimes
25337453Sbde#endif
2541590Srgrimes
2551590Srgrimes_LIBCPP_NORETURN
2561590Srgrimesvoid
2571590Srgrimesnested_exception::rethrow_nested() const
2581590Srgrimes{
2591590Srgrimes    if (__ptr_ == nullptr)
2601590Srgrimes        terminate();
2611590Srgrimes    rethrow_exception(__ptr_);
2621590Srgrimes}
2631590Srgrimes
2641590Srgrimes#if !defined(__GLIBCXX__)
2651590Srgrimes
2661590Srgrimesexception_ptr current_exception() _NOEXCEPT
2671590Srgrimes{
2681590Srgrimes#if HAVE_DEPENDENT_EH_ABI
2691590Srgrimes    // be nicer if there was a constructor that took a ptr, then
2701590Srgrimes    // this whole function would be just:
2711590Srgrimes    //    return exception_ptr(__cxa_current_primary_exception());
2721590Srgrimes    exception_ptr ptr;
2731590Srgrimes    ptr.__ptr_ = __cxa_current_primary_exception();
2741590Srgrimes    return ptr;
2751590Srgrimes#else
2761590Srgrimes#   if defined(_MSC_VER) && ! defined(__clang__)
2771590Srgrimes        _LIBCPP_WARNING( "exception_ptr not yet implemented" )
2781590Srgrimes#   else
2791590Srgrimes#       warning exception_ptr not yet implemented
2801590Srgrimes#   endif
2811590Srgrimes    printf("exception_ptr not yet implemented\n");
2821590Srgrimes    ::abort();
2831590Srgrimes#endif
2841590Srgrimes}
2851590Srgrimes
2861590Srgrimes#endif  // !__GLIBCXX__
2871590Srgrimes
2881590Srgrimes_LIBCPP_NORETURN
2891590Srgrimesvoid rethrow_exception(exception_ptr p)
2901590Srgrimes{
2911590Srgrimes#if HAVE_DEPENDENT_EH_ABI
292    __cxa_rethrow_primary_exception(p.__ptr_);
293    // if p.__ptr_ is NULL, above returns so we terminate
294    terminate();
295#elif defined(__GLIBCXX__)
296    rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
297#else
298#   if defined(_MSC_VER) && ! defined(__clang__)
299        _LIBCPP_WARNING("exception_ptr not yet implemented")
300#   else
301#       warning exception_ptr not yet implemented
302#   endif
303    printf("exception_ptr not yet implemented\n");
304    ::abort();
305#endif
306}
307} // std
308