Home | History | Annotate | Download | only in src
      1 //===------------------------ exception.cpp -------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #include <stdlib.h>
     10 
     11 #include "exception"
     12 
     13 #ifndef __has_include
     14 #define __has_include(inc) 0
     15 #endif
     16 
     17 #ifdef __APPLE__
     18   #include <cxxabi.h>
     19 
     20   using namespace __cxxabiv1;
     21   #define HAVE_DEPENDENT_EH_ABI 1
     22   #ifndef _LIBCPPABI_VERSION
     23     using namespace __cxxabiapple;
     24     // On Darwin, there are two STL shared libraries and a lower level ABI
     25     // shared libray.  The globals holding the current terminate handler and
     26     // current unexpected handler are in the ABI library.
     27     #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
     28     #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
     29   #endif  // _LIBCPPABI_VERSION
     30 #elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
     31   #include <cxxabi.h>
     32   using namespace __cxxabiv1;
     33   #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
     34     #define HAVE_DEPENDENT_EH_ABI 1
     35   #endif
     36 #elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>)
     37   static std::terminate_handler  __terminate_handler;
     38   static std::unexpected_handler __unexpected_handler;
     39 #endif // __has_include(<cxxabi.h>)
     40 
     41 namespace std
     42 {
     43 
     44 #if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
     45 
     46 // libcxxrt provides implementations of these functions itself.
     47 unexpected_handler
     48 set_unexpected(unexpected_handler func) _NOEXCEPT
     49 {
     50     return __sync_lock_test_and_set(&__unexpected_handler, func);
     51 }
     52 
     53 unexpected_handler
     54 get_unexpected() _NOEXCEPT
     55 {
     56     return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
     57 }
     58 
     59 _LIBCPP_NORETURN
     60 void
     61 unexpected()
     62 {
     63     (*get_unexpected())();
     64     // unexpected handler should not return
     65     terminate();
     66 }
     67 
     68 terminate_handler
     69 set_terminate(terminate_handler func) _NOEXCEPT
     70 {
     71     return __sync_lock_test_and_set(&__terminate_handler, func);
     72 }
     73 
     74 terminate_handler
     75 get_terminate() _NOEXCEPT
     76 {
     77     return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
     78 }
     79 
     80 #ifndef EMSCRIPTEN // We provide this in JS
     81 _LIBCPP_NORETURN
     82 void
     83 terminate() _NOEXCEPT
     84 {
     85 #ifndef _LIBCPP_NO_EXCEPTIONS
     86     try
     87     {
     88 #endif  // _LIBCPP_NO_EXCEPTIONS
     89         (*get_terminate())();
     90         // handler should not return
     91         ::abort ();
     92 #ifndef _LIBCPP_NO_EXCEPTIONS
     93     }
     94     catch (...)
     95     {
     96         // handler should not throw exception
     97         ::abort ();
     98     }
     99 #endif  // _LIBCPP_NO_EXCEPTIONS
    100 }
    101 #endif // !EMSCRIPTEN
    102 #endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
    103 
    104 #if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(EMSCRIPTEN)
    105 bool uncaught_exception() _NOEXCEPT
    106 {
    107 #if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
    108     // on Darwin, there is a helper function so __cxa_get_globals is private
    109     return __cxa_uncaught_exception();
    110 #else  // __APPLE__
    111     #warning uncaught_exception not yet implemented
    112     ::abort();
    113 #endif  // __APPLE__
    114 }
    115 
    116 #ifndef _LIBCPPABI_VERSION
    117 
    118 exception::~exception() _NOEXCEPT
    119 {
    120 }
    121 
    122 const char* exception::what() const _NOEXCEPT
    123 {
    124   return "std::exception";
    125 }
    126 
    127 #endif  // _LIBCPPABI_VERSION
    128 #endif //LIBCXXRT
    129 #if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
    130 
    131 bad_exception::~bad_exception() _NOEXCEPT
    132 {
    133 }
    134 
    135 const char* bad_exception::what() const _NOEXCEPT
    136 {
    137   return "std::bad_exception";
    138 }
    139 
    140 #endif
    141 
    142 
    143 exception_ptr::~exception_ptr() _NOEXCEPT
    144 {
    145 #if HAVE_DEPENDENT_EH_ABI
    146     __cxa_decrement_exception_refcount(__ptr_);
    147 #else
    148     #warning exception_ptr not yet implemented
    149     ::abort();
    150 #endif  // __APPLE__
    151 }
    152 
    153 exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    154     : __ptr_(other.__ptr_)
    155 {
    156 #if HAVE_DEPENDENT_EH_ABI
    157     __cxa_increment_exception_refcount(__ptr_);
    158 #else
    159     #warning exception_ptr not yet implemented
    160     ::abort();
    161 #endif  // __APPLE__
    162 }
    163 
    164 exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
    165 {
    166 #if HAVE_DEPENDENT_EH_ABI
    167     if (__ptr_ != other.__ptr_)
    168     {
    169         __cxa_increment_exception_refcount(other.__ptr_);
    170         __cxa_decrement_exception_refcount(__ptr_);
    171         __ptr_ = other.__ptr_;
    172     }
    173     return *this;
    174 #else  // __APPLE__
    175     #warning exception_ptr not yet implemented
    176     ::abort();
    177 #endif  // __APPLE__
    178 }
    179 
    180 nested_exception::nested_exception() _NOEXCEPT
    181     : __ptr_(current_exception())
    182 {
    183 }
    184 
    185 nested_exception::~nested_exception() _NOEXCEPT
    186 {
    187 }
    188 
    189 _LIBCPP_NORETURN
    190 void
    191 nested_exception::rethrow_nested() const
    192 {
    193     if (__ptr_ == nullptr)
    194         terminate();
    195     rethrow_exception(__ptr_);
    196 }
    197 
    198 
    199 exception_ptr current_exception() _NOEXCEPT
    200 {
    201 #if HAVE_DEPENDENT_EH_ABI
    202     // be nicer if there was a constructor that took a ptr, then
    203     // this whole function would be just:
    204     //    return exception_ptr(__cxa_current_primary_exception());
    205     exception_ptr ptr;
    206     ptr.__ptr_ = __cxa_current_primary_exception();
    207     return ptr;
    208 #else  // __APPLE__
    209     #warning exception_ptr not yet implemented
    210     ::abort();
    211 #endif  // __APPLE__
    212 }
    213 
    214 _LIBCPP_NORETURN
    215 void rethrow_exception(exception_ptr p)
    216 {
    217 #if HAVE_DEPENDENT_EH_ABI
    218     __cxa_rethrow_primary_exception(p.__ptr_);
    219     // if p.__ptr_ is NULL, above returns so we terminate
    220     terminate();
    221 #else  // __APPLE__
    222     #warning exception_ptr not yet implemented
    223     ::abort();
    224 #endif  // __APPLE__
    225 }
    226 } // std
    227