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