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