exception.cpp revision 249989
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
41namespace std
42{
43
44#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
45
46// libcxxrt provides implementations of these functions itself.
47unexpected_handler
48set_unexpected(unexpected_handler func) _NOEXCEPT
49{
50    return __sync_lock_test_and_set(&__unexpected_handler, func);
51}
52
53unexpected_handler
54get_unexpected() _NOEXCEPT
55{
56    return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
57}
58
59_LIBCPP_NORETURN
60void
61unexpected()
62{
63    (*get_unexpected())();
64    // unexpected handler should not return
65    terminate();
66}
67
68terminate_handler
69set_terminate(terminate_handler func) _NOEXCEPT
70{
71    return __sync_lock_test_and_set(&__terminate_handler, func);
72}
73
74terminate_handler
75get_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
82void
83terminate() _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)
105bool 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
118exception::~exception() _NOEXCEPT
119{
120}
121
122const 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
131bad_exception::~bad_exception() _NOEXCEPT
132{
133}
134
135const char* bad_exception::what() const _NOEXCEPT
136{
137  return "std::bad_exception";
138}
139
140#endif
141
142
143exception_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
153exception_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
164exception_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
180nested_exception::nested_exception() _NOEXCEPT
181    : __ptr_(current_exception())
182{
183}
184
185nested_exception::~nested_exception() _NOEXCEPT
186{
187}
188
189_LIBCPP_NORETURN
190void
191nested_exception::rethrow_nested() const
192{
193    if (__ptr_ == nullptr)
194        terminate();
195    rethrow_exception(__ptr_);
196}
197
198
199exception_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
215void 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