exception.cpp revision 232924
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
117bad_exception::~bad_exception() _NOEXCEPT
118{
119}
120
121const char* exception::what() const _NOEXCEPT
122{
123  return "std::exception";
124}
125
126const char* bad_exception::what() const _NOEXCEPT
127{
128  return "std::bad_exception";
129}
130
131#endif  // _LIBCPPABI_VERSION
132#endif //LIBCXXRT
133
134exception_ptr::~exception_ptr() _NOEXCEPT
135{
136#if HAVE_DEPENDENT_EH_ABI
137    __cxa_decrement_exception_refcount(__ptr_);
138#else
139    #warning exception_ptr not yet implemented
140    ::abort();
141#endif  // __APPLE__
142}
143
144exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
145    : __ptr_(other.__ptr_)
146{
147#if HAVE_DEPENDENT_EH_ABI
148    __cxa_increment_exception_refcount(__ptr_);
149#else
150    #warning exception_ptr not yet implemented
151    ::abort();
152#endif  // __APPLE__
153}
154
155exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
156{
157#if HAVE_DEPENDENT_EH_ABI
158    if (__ptr_ != other.__ptr_)
159    {
160        __cxa_increment_exception_refcount(other.__ptr_);
161        __cxa_decrement_exception_refcount(__ptr_);
162        __ptr_ = other.__ptr_;
163    }
164    return *this;
165#else  // __APPLE__
166    #warning exception_ptr not yet implemented
167    ::abort();
168#endif  // __APPLE__
169}
170
171nested_exception::nested_exception() _NOEXCEPT
172    : __ptr_(current_exception())
173{
174}
175
176nested_exception::~nested_exception() _NOEXCEPT
177{
178}
179
180_ATTRIBUTE(noreturn)
181void
182nested_exception::rethrow_nested() const
183{
184    if (__ptr_ == nullptr)
185        terminate();
186    rethrow_exception(__ptr_);
187}
188
189
190exception_ptr current_exception() _NOEXCEPT
191{
192#if HAVE_DEPENDENT_EH_ABI
193    // be nicer if there was a constructor that took a ptr, then
194    // this whole function would be just:
195    //    return exception_ptr(__cxa_current_primary_exception());
196    exception_ptr ptr;
197    ptr.__ptr_ = __cxa_current_primary_exception();
198    return ptr;
199#else  // __APPLE__
200    #warning exception_ptr not yet implemented
201    ::abort();
202#endif  // __APPLE__
203}
204
205_ATTRIBUTE(noreturn)
206void rethrow_exception(exception_ptr p)
207{
208#if HAVE_DEPENDENT_EH_ABI
209    __cxa_rethrow_primary_exception(p.__ptr_);
210    // if p.__ptr_ is NULL, above returns so we terminate
211    terminate();
212#else  // __APPLE__
213    #warning exception_ptr not yet implemented
214    ::abort();
215#endif  // __APPLE__
216}
217} // std
218