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 #include <stdio.h>
     11 
     12 #include "exception"
     13 #include "new"
     14 
     15 #ifndef __has_include
     16 #define __has_include(inc) 0
     17 #endif
     18 
     19 #if defined(__APPLE__) && !defined(LIBCXXRT)
     20   #include <cxxabi.h>
     21 
     22   using namespace __cxxabiv1;
     23   #define HAVE_DEPENDENT_EH_ABI 1
     24   #ifndef _LIBCPPABI_VERSION
     25     using namespace __cxxabiapple;
     26     // On Darwin, there are two STL shared libraries and a lower level ABI
     27     // shared library.  The globals holding the current terminate handler and
     28     // current unexpected handler are in the ABI library.
     29     #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
     30     #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
     31   #endif  // _LIBCPPABI_VERSION
     32 #elif defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI) || __has_include(<cxxabi.h>)
     33   #include <cxxabi.h>
     34   using namespace __cxxabiv1;
     35   #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
     36     #define HAVE_DEPENDENT_EH_ABI 1
     37   #endif
     38 #elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>)
     39   static std::terminate_handler  __terminate_handler;
     40   static std::unexpected_handler __unexpected_handler;
     41 #endif // __has_include(<cxxabi.h>)
     42 
     43 namespace std
     44 {
     45 
     46 #if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
     47 
     48 // libcxxrt provides implementations of these functions itself.
     49 unexpected_handler
     50 set_unexpected(unexpected_handler func) _NOEXCEPT
     51 {
     52     return __sync_lock_test_and_set(&__unexpected_handler, func);
     53 }
     54 
     55 unexpected_handler
     56 get_unexpected() _NOEXCEPT
     57 {
     58     return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
     59 }
     60 
     61 _LIBCPP_NORETURN
     62 void
     63 unexpected()
     64 {
     65     (*get_unexpected())();
     66     // unexpected handler should not return
     67     terminate();
     68 }
     69 
     70 terminate_handler
     71 set_terminate(terminate_handler func) _NOEXCEPT
     72 {
     73     return __sync_lock_test_and_set(&__terminate_handler, func);
     74 }
     75 
     76 terminate_handler
     77 get_terminate() _NOEXCEPT
     78 {
     79     return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
     80 }
     81 
     82 #ifndef __EMSCRIPTEN__ // We provide this in JS
     83 _LIBCPP_NORETURN
     84 void
     85 terminate() _NOEXCEPT
     86 {
     87 #ifndef _LIBCPP_NO_EXCEPTIONS
     88     try
     89     {
     90 #endif  // _LIBCPP_NO_EXCEPTIONS
     91         (*get_terminate())();
     92         // handler should not return
     93         fprintf(stderr, "terminate_handler unexpectedly returned\n");
     94         ::abort();
     95 #ifndef _LIBCPP_NO_EXCEPTIONS
     96     }
     97     catch (...)
     98     {
     99         // handler should not throw exception
    100         fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
    101         ::abort();
    102     }
    103 #endif  // _LIBCPP_NO_EXCEPTIONS
    104 }
    105 #endif // !__EMSCRIPTEN__
    106 #endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
    107 
    108 #if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__)
    109 bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
    110 
    111 int uncaught_exceptions() _NOEXCEPT
    112 {
    113 #if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
    114    // on Darwin, there is a helper function so __cxa_get_globals is private
    115 # if _LIBCPPABI_VERSION > 1101
    116     return __cxa_uncaught_exceptions();
    117 # else
    118     return __cxa_uncaught_exception() ? 1 : 0;
    119 # endif
    120 #else  // __APPLE__
    121 #   if defined(_MSC_VER) && ! defined(__clang__)
    122         _LIBCPP_WARNING("uncaught_exceptions not yet implemented")
    123 #   else
    124 #       warning uncaught_exception not yet implemented
    125 #   endif
    126     fprintf(stderr, "uncaught_exceptions not yet implemented\n");
    127     ::abort();
    128 #endif  // __APPLE__
    129 }
    130 
    131 
    132 #ifndef _LIBCPPABI_VERSION
    133 
    134 exception::~exception() _NOEXCEPT
    135 {
    136 }
    137 
    138 const char* exception::what() const _NOEXCEPT
    139 {
    140   return "std::exception";
    141 }
    142 
    143 #endif  // _LIBCPPABI_VERSION
    144 #endif //LIBCXXRT
    145 #if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
    146 
    147 bad_exception::~bad_exception() _NOEXCEPT
    148 {
    149 }
    150 
    151 const char* bad_exception::what() const _NOEXCEPT
    152 {
    153   return "std::bad_exception";
    154 }
    155 
    156 #endif
    157 
    158 #if defined(__GLIBCXX__)
    159 
    160 // libsupc++ does not implement the dependent EH ABI and the functionality
    161 // it uses to implement std::exception_ptr (which it declares as an alias of
    162 // std::__exception_ptr::exception_ptr) is not directly exported to clients. So
    163 // we have little choice but to hijack std::__exception_ptr::exception_ptr's
    164 // (which fortunately has the same layout as our std::exception_ptr) copy
    165 // constructor, assignment operator and destructor (which are part of its
    166 // stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
    167 // function.
    168 
    169 namespace __exception_ptr
    170 {
    171 
    172 struct exception_ptr
    173 {
    174     void* __ptr_;
    175 
    176     exception_ptr(const exception_ptr&) _NOEXCEPT;
    177     exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
    178     ~exception_ptr() _NOEXCEPT;
    179 };
    180 
    181 }
    182 
    183 _LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
    184 
    185 #endif
    186 
    187 exception_ptr::~exception_ptr() _NOEXCEPT
    188 {
    189 #if HAVE_DEPENDENT_EH_ABI
    190     __cxa_decrement_exception_refcount(__ptr_);
    191 #elif defined(__GLIBCXX__)
    192     reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
    193 #else
    194 #   if defined(_MSC_VER) && ! defined(__clang__)
    195         _LIBCPP_WARNING("exception_ptr not yet implemented")
    196 #   else
    197 #       warning exception_ptr not yet implemented
    198 #   endif
    199     fprintf(stderr, "exception_ptr not yet implemented\n");
    200     ::abort();
    201 #endif
    202 }
    203 
    204 exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    205     : __ptr_(other.__ptr_)
    206 {
    207 #if HAVE_DEPENDENT_EH_ABI
    208     __cxa_increment_exception_refcount(__ptr_);
    209 #elif defined(__GLIBCXX__)
    210     new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
    211         reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
    212 #else
    213 #   if defined(_MSC_VER) && ! defined(__clang__)
    214         _LIBCPP_WARNING("exception_ptr not yet implemented")
    215 #   else
    216 #       warning exception_ptr not yet implemented
    217 #   endif
    218     fprintf(stderr, "exception_ptr not yet implemented\n");
    219     ::abort();
    220 #endif
    221 }
    222 
    223 exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
    224 {
    225 #if HAVE_DEPENDENT_EH_ABI
    226     if (__ptr_ != other.__ptr_)
    227     {
    228         __cxa_increment_exception_refcount(other.__ptr_);
    229         __cxa_decrement_exception_refcount(__ptr_);
    230         __ptr_ = other.__ptr_;
    231     }
    232     return *this;
    233 #elif defined(__GLIBCXX__)
    234     *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
    235         reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
    236     return *this;
    237 #else
    238 #   if defined(_MSC_VER) && ! defined(__clang__)
    239         _LIBCPP_WARNING("exception_ptr not yet implemented")
    240 #   else
    241 #       warning exception_ptr not yet implemented
    242 #   endif
    243     fprintf(stderr, "exception_ptr not yet implemented\n");
    244     ::abort();
    245 #endif
    246 }
    247 
    248 nested_exception::nested_exception() _NOEXCEPT
    249     : __ptr_(current_exception())
    250 {
    251 }
    252 
    253 #if !defined(__GLIBCXX__)
    254 
    255 nested_exception::~nested_exception() _NOEXCEPT
    256 {
    257 }
    258 
    259 #endif
    260 
    261 _LIBCPP_NORETURN
    262 void
    263 nested_exception::rethrow_nested() const
    264 {
    265     if (__ptr_ == nullptr)
    266         terminate();
    267     rethrow_exception(__ptr_);
    268 }
    269 
    270 #if !defined(__GLIBCXX__)
    271 
    272 exception_ptr current_exception() _NOEXCEPT
    273 {
    274 #if HAVE_DEPENDENT_EH_ABI
    275     // be nicer if there was a constructor that took a ptr, then
    276     // this whole function would be just:
    277     //    return exception_ptr(__cxa_current_primary_exception());
    278     exception_ptr ptr;
    279     ptr.__ptr_ = __cxa_current_primary_exception();
    280     return ptr;
    281 #else
    282 #   if defined(_MSC_VER) && ! defined(__clang__)
    283         _LIBCPP_WARNING( "exception_ptr not yet implemented" )
    284 #   else
    285 #       warning exception_ptr not yet implemented
    286 #   endif
    287     fprintf(stderr, "exception_ptr not yet implemented\n");
    288     ::abort();
    289 #endif
    290 }
    291 
    292 #endif  // !__GLIBCXX__
    293 
    294 _LIBCPP_NORETURN
    295 void rethrow_exception(exception_ptr p)
    296 {
    297 #if HAVE_DEPENDENT_EH_ABI
    298     __cxa_rethrow_primary_exception(p.__ptr_);
    299     // if p.__ptr_ is NULL, above returns so we terminate
    300     terminate();
    301 #elif defined(__GLIBCXX__)
    302     rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
    303 #else
    304 #   if defined(_MSC_VER) && ! defined(__clang__)
    305         _LIBCPP_WARNING("exception_ptr not yet implemented")
    306 #   else
    307 #       warning exception_ptr not yet implemented
    308 #   endif
    309     fprintf(stderr, "exception_ptr not yet implemented\n");
    310     ::abort();
    311 #endif
    312 }
    313 } // std
    314