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