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