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