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