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