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