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 #if __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 #else  // __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 _LIBCPP_NORETURN
     81 void
     82 terminate() _NOEXCEPT
     83 {
     84 #ifndef _LIBCPP_NO_EXCEPTIONS
     85     try
     86     {
     87 #endif  // _LIBCPP_NO_EXCEPTIONS
     88         (*get_terminate())();
     89         // handler should not return
     90         ::abort ();
     91 #ifndef _LIBCPP_NO_EXCEPTIONS
     92     }
     93     catch (...)
     94     {
     95         // handler should not throw exception
     96         ::abort ();
     97     }
     98 #endif  // _LIBCPP_NO_EXCEPTIONS
     99 }
    100 #endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
    101 
    102 #if !defined(LIBCXXRT) && !defined(__GLIBCXX__)
    103 bool uncaught_exception() _NOEXCEPT
    104 {
    105 #if __APPLE__ || defined(_LIBCPPABI_VERSION)
    106     // on Darwin, there is a helper function so __cxa_get_globals is private
    107     return __cxa_uncaught_exception();
    108 #else  // __APPLE__
    109     #warning uncaught_exception not yet implemented
    110     ::abort();
    111 #endif  // __APPLE__
    112 }
    113 
    114 #ifndef _LIBCPPABI_VERSION
    115 
    116 exception::~exception() _NOEXCEPT
    117 {
    118 }
    119 
    120 const char* exception::what() const _NOEXCEPT
    121 {
    122   return "std::exception";
    123 }
    124 
    125 #endif  // _LIBCPPABI_VERSION
    126 #endif //LIBCXXRT
    127 #if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
    128 
    129 bad_exception::~bad_exception() _NOEXCEPT
    130 {
    131 }
    132 
    133 const char* bad_exception::what() const _NOEXCEPT
    134 {
    135   return "std::bad_exception";
    136 }
    137 
    138 #endif
    139 
    140 
    141 exception_ptr::~exception_ptr() _NOEXCEPT
    142 {
    143 #if HAVE_DEPENDENT_EH_ABI
    144     __cxa_decrement_exception_refcount(__ptr_);
    145 #else
    146     #warning exception_ptr not yet implemented
    147     ::abort();
    148 #endif  // __APPLE__
    149 }
    150 
    151 exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    152     : __ptr_(other.__ptr_)
    153 {
    154 #if HAVE_DEPENDENT_EH_ABI
    155     __cxa_increment_exception_refcount(__ptr_);
    156 #else
    157     #warning exception_ptr not yet implemented
    158     ::abort();
    159 #endif  // __APPLE__
    160 }
    161 
    162 exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
    163 {
    164 #if HAVE_DEPENDENT_EH_ABI
    165     if (__ptr_ != other.__ptr_)
    166     {
    167         __cxa_increment_exception_refcount(other.__ptr_);
    168         __cxa_decrement_exception_refcount(__ptr_);
    169         __ptr_ = other.__ptr_;
    170     }
    171     return *this;
    172 #else  // __APPLE__
    173     #warning exception_ptr not yet implemented
    174     ::abort();
    175 #endif  // __APPLE__
    176 }
    177 
    178 nested_exception::nested_exception() _NOEXCEPT
    179     : __ptr_(current_exception())
    180 {
    181 }
    182 
    183 nested_exception::~nested_exception() _NOEXCEPT
    184 {
    185 }
    186 
    187 _LIBCPP_NORETURN
    188 void
    189 nested_exception::rethrow_nested() const
    190 {
    191     if (__ptr_ == nullptr)
    192         terminate();
    193     rethrow_exception(__ptr_);
    194 }
    195 
    196 
    197 exception_ptr current_exception() _NOEXCEPT
    198 {
    199 #if HAVE_DEPENDENT_EH_ABI
    200     // be nicer if there was a constructor that took a ptr, then
    201     // this whole function would be just:
    202     //    return exception_ptr(__cxa_current_primary_exception());
    203     exception_ptr ptr;
    204     ptr.__ptr_ = __cxa_current_primary_exception();
    205     return ptr;
    206 #else  // __APPLE__
    207     #warning exception_ptr not yet implemented
    208     ::abort();
    209 #endif  // __APPLE__
    210 }
    211 
    212 _LIBCPP_NORETURN
    213 void rethrow_exception(exception_ptr p)
    214 {
    215 #if HAVE_DEPENDENT_EH_ABI
    216     __cxa_rethrow_primary_exception(p.__ptr_);
    217     // if p.__ptr_ is NULL, above returns so we terminate
    218     terminate();
    219 #else  // __APPLE__
    220     #warning exception_ptr not yet implemented
    221     ::abort();
    222 #endif  // __APPLE__
    223 }
    224 } // std
    225