exception.cpp revision 232969
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#if __APPLE__
14  #include <cxxabi.h>
15
16  using namespace __cxxabiv1;
17  #define HAVE_DEPENDENT_EH_ABI 1
18  #ifndef _LIBCPPABI_VERSION
19    using namespace __cxxabiapple;
20    // On Darwin, there are two STL shared libraries and a lower level ABI
21    // shared libray.  The globals holding the current terminate handler and
22    // current unexpected handler are in the ABI library.
23    #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
24    #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
25  #endif  // _LIBCPPABI_VERSION
26#elif defined(LIBCXXRT)
27  #include <cxxabi.h>
28  using namespace __cxxabiv1;
29  #define HAVE_DEPENDENT_EH_ABI 1
30#else  // __APPLE__
31  static std::terminate_handler  __terminate_handler;
32  static std::unexpected_handler __unexpected_handler;
33#endif  // __APPLE__
34
35namespace std
36{
37
38#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
39
40// libcxxrt provides implementations of these functions itself.
41unexpected_handler
42set_unexpected(unexpected_handler func) _NOEXCEPT
43{
44    return __sync_lock_test_and_set(&__unexpected_handler, func);
45}
46
47unexpected_handler
48get_unexpected() _NOEXCEPT
49{
50    return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
51}
52
53_ATTRIBUTE(noreturn)
54void
55unexpected()
56{
57    (*get_unexpected())();
58    // unexpected handler should not return
59    terminate();
60}
61
62terminate_handler
63set_terminate(terminate_handler func) _NOEXCEPT
64{
65    return __sync_lock_test_and_set(&__terminate_handler, func);
66}
67
68terminate_handler
69get_terminate() _NOEXCEPT
70{
71    return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
72}
73
74_ATTRIBUTE(noreturn)
75void
76terminate() _NOEXCEPT
77{
78#ifndef _LIBCPP_NO_EXCEPTIONS
79    try
80    {
81#endif  // _LIBCPP_NO_EXCEPTIONS
82        (*get_terminate())();
83        // handler should not return
84        ::abort ();
85#ifndef _LIBCPP_NO_EXCEPTIONS
86    }
87    catch (...)
88    {
89        // handler should not throw exception
90        ::abort ();
91    }
92#endif  // _LIBCPP_NO_EXCEPTIONS
93}
94#endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
95
96#ifndef LIBCXXRT
97bool uncaught_exception() _NOEXCEPT
98{
99#if __APPLE__
100    // on Darwin, there is a helper function so __cxa_get_globals is private
101    return __cxa_uncaught_exception();
102#elif LIBCXXRT
103    __cxa_eh_globals * globals = __cxa_get_globals();
104    return (globals->uncaughtExceptions != 0);
105#else  // __APPLE__
106    #warning uncaught_exception not yet implemented
107    ::abort();
108#endif  // __APPLE__
109}
110
111#ifndef _LIBCPPABI_VERSION
112
113exception::~exception() _NOEXCEPT
114{
115}
116
117const char* exception::what() const _NOEXCEPT
118{
119  return "std::exception";
120}
121
122#endif  // _LIBCPPABI_VERSION
123#endif //LIBCXXRT
124#ifndef _LIBCPPABI_VERSION
125
126bad_exception::~bad_exception() _NOEXCEPT
127{
128}
129
130const char* bad_exception::what() const _NOEXCEPT
131{
132  return "std::bad_exception";
133}
134
135#endif
136
137
138exception_ptr::~exception_ptr() _NOEXCEPT
139{
140#if HAVE_DEPENDENT_EH_ABI
141    __cxa_decrement_exception_refcount(__ptr_);
142#else
143    #warning exception_ptr not yet implemented
144    ::abort();
145#endif  // __APPLE__
146}
147
148exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
149    : __ptr_(other.__ptr_)
150{
151#if HAVE_DEPENDENT_EH_ABI
152    __cxa_increment_exception_refcount(__ptr_);
153#else
154    #warning exception_ptr not yet implemented
155    ::abort();
156#endif  // __APPLE__
157}
158
159exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
160{
161#if HAVE_DEPENDENT_EH_ABI
162    if (__ptr_ != other.__ptr_)
163    {
164        __cxa_increment_exception_refcount(other.__ptr_);
165        __cxa_decrement_exception_refcount(__ptr_);
166        __ptr_ = other.__ptr_;
167    }
168    return *this;
169#else  // __APPLE__
170    #warning exception_ptr not yet implemented
171    ::abort();
172#endif  // __APPLE__
173}
174
175nested_exception::nested_exception() _NOEXCEPT
176    : __ptr_(current_exception())
177{
178}
179
180nested_exception::~nested_exception() _NOEXCEPT
181{
182}
183
184_ATTRIBUTE(noreturn)
185void
186nested_exception::rethrow_nested() const
187{
188    if (__ptr_ == nullptr)
189        terminate();
190    rethrow_exception(__ptr_);
191}
192
193
194exception_ptr current_exception() _NOEXCEPT
195{
196#if HAVE_DEPENDENT_EH_ABI
197    // be nicer if there was a constructor that took a ptr, then
198    // this whole function would be just:
199    //    return exception_ptr(__cxa_current_primary_exception());
200    exception_ptr ptr;
201    ptr.__ptr_ = __cxa_current_primary_exception();
202    return ptr;
203#else  // __APPLE__
204    #warning exception_ptr not yet implemented
205    ::abort();
206#endif  // __APPLE__
207}
208
209_ATTRIBUTE(noreturn)
210void rethrow_exception(exception_ptr p)
211{
212#if HAVE_DEPENDENT_EH_ABI
213    __cxa_rethrow_primary_exception(p.__ptr_);
214    // if p.__ptr_ is NULL, above returns so we terminate
215    terminate();
216#else  // __APPLE__
217    #warning exception_ptr not yet implemented
218    ::abort();
219#endif  // __APPLE__
220}
221} // std
222