• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  #include "new"
14  
15  #ifndef __has_include
16  #define __has_include(inc) 0
17  #endif
18  
19  #if defined(__APPLE__) && !defined(LIBCXXRT)
20    #include <cxxabi.h>
21  
22    using namespace __cxxabiv1;
23    #define HAVE_DEPENDENT_EH_ABI 1
24    #ifndef _LIBCPPABI_VERSION
25      using namespace __cxxabiapple;
26      // On Darwin, there are two STL shared libraries and a lower level ABI
27      // shared library.  The globals holding the current terminate handler and
28      // current unexpected handler are in the ABI library.
29      #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
30      #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
31    #endif  // _LIBCPPABI_VERSION
32  #elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
33    #include <cxxabi.h>
34    using namespace __cxxabiv1;
35    #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
36      #define HAVE_DEPENDENT_EH_ABI 1
37    #endif
38  #elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>)
39    static std::terminate_handler  __terminate_handler;
40    static std::unexpected_handler __unexpected_handler;
41  #endif // __has_include(<cxxabi.h>)
42  
43  namespace std
44  {
45  
46  #if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
47  
48  // libcxxrt provides implementations of these functions itself.
49  unexpected_handler
set_unexpected(unexpected_handler func)50  set_unexpected(unexpected_handler func) _NOEXCEPT
51  {
52      return __sync_lock_test_and_set(&__unexpected_handler, func);
53  }
54  
55  unexpected_handler
get_unexpected()56  get_unexpected() _NOEXCEPT
57  {
58      return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
59  }
60  
61  _LIBCPP_NORETURN
62  void
unexpected()63  unexpected()
64  {
65      (*get_unexpected())();
66      // unexpected handler should not return
67      terminate();
68  }
69  
70  terminate_handler
set_terminate(terminate_handler func)71  set_terminate(terminate_handler func) _NOEXCEPT
72  {
73      return __sync_lock_test_and_set(&__terminate_handler, func);
74  }
75  
76  terminate_handler
get_terminate()77  get_terminate() _NOEXCEPT
78  {
79      return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
80  }
81  
82  #ifndef __EMSCRIPTEN__ // We provide this in JS
83  _LIBCPP_NORETURN
84  void
terminate()85  terminate() _NOEXCEPT
86  {
87  #ifndef _LIBCPP_NO_EXCEPTIONS
88      try
89      {
90  #endif  // _LIBCPP_NO_EXCEPTIONS
91          (*get_terminate())();
92          // handler should not return
93          printf("terminate_handler unexpectedly returned\n");
94          ::abort();
95  #ifndef _LIBCPP_NO_EXCEPTIONS
96      }
97      catch (...)
98      {
99          // handler should not throw exception
100          printf("terminate_handler unexpectedly threw an exception\n");
101          ::abort();
102      }
103  #endif  // _LIBCPP_NO_EXCEPTIONS
104  }
105  #endif // !__EMSCRIPTEN__
106  #endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
107  
108  #if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__)
uncaught_exception()109  bool uncaught_exception() _NOEXCEPT
110  {
111  #if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
112      // on Darwin, there is a helper function so __cxa_get_globals is private
113      return __cxa_uncaught_exception();
114  #else  // __APPLE__
115  #   if defined(_MSC_VER) && ! defined(__clang__)
116          _LIBCPP_WARNING("uncaught_exception not yet implemented")
117  #   else
118  #       warning uncaught_exception not yet implemented
119  #   endif
120      printf("uncaught_exception not yet implemented\n");
121      ::abort();
122  #endif  // __APPLE__
123  }
124  
125  
126  #ifndef _LIBCPPABI_VERSION
127  
~exception()128  exception::~exception() _NOEXCEPT
129  {
130  }
131  
what() const132  const char* exception::what() const _NOEXCEPT
133  {
134    return "std::exception";
135  }
136  
137  #endif  // _LIBCPPABI_VERSION
138  #endif //LIBCXXRT
139  #if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
140  
~bad_exception()141  bad_exception::~bad_exception() _NOEXCEPT
142  {
143  }
144  
what() const145  const char* bad_exception::what() const _NOEXCEPT
146  {
147    return "std::bad_exception";
148  }
149  
150  #endif
151  
152  #if defined(__GLIBCXX__)
153  
154  // libsupc++ does not implement the dependent EH ABI and the functionality
155  // it uses to implement std::exception_ptr (which it declares as an alias of
156  // std::__exception_ptr::exception_ptr) is not directly exported to clients. So
157  // we have little choice but to hijack std::__exception_ptr::exception_ptr's
158  // (which fortunately has the same layout as our std::exception_ptr) copy
159  // constructor, assignment operator and destructor (which are part of its
160  // stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
161  // function.
162  
163  namespace __exception_ptr
164  {
165  
166  struct exception_ptr
167  {
168      void* __ptr_;
169  
170      exception_ptr(const exception_ptr&) _NOEXCEPT;
171      exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
172      ~exception_ptr() _NOEXCEPT;
173  };
174  
175  }
176  
177  _LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
178  
179  #endif
180  
~exception_ptr()181  exception_ptr::~exception_ptr() _NOEXCEPT
182  {
183  #if HAVE_DEPENDENT_EH_ABI
184      __cxa_decrement_exception_refcount(__ptr_);
185  #elif defined(__GLIBCXX__)
186      reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
187  #else
188  #   if defined(_MSC_VER) && ! defined(__clang__)
189          _LIBCPP_WARNING("exception_ptr not yet implemented")
190  #   else
191  #       warning exception_ptr not yet implemented
192  #   endif
193      printf("exception_ptr not yet implemented\n");
194      ::abort();
195  #endif
196  }
197  
exception_ptr(const exception_ptr & other)198  exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
199      : __ptr_(other.__ptr_)
200  {
201  #if HAVE_DEPENDENT_EH_ABI
202      __cxa_increment_exception_refcount(__ptr_);
203  #elif defined(__GLIBCXX__)
204      new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
205          reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
206  #else
207  #   if defined(_MSC_VER) && ! defined(__clang__)
208          _LIBCPP_WARNING("exception_ptr not yet implemented")
209  #   else
210  #       warning exception_ptr not yet implemented
211  #   endif
212      printf("exception_ptr not yet implemented\n");
213      ::abort();
214  #endif
215  }
216  
operator =(const exception_ptr & other)217  exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
218  {
219  #if HAVE_DEPENDENT_EH_ABI
220      if (__ptr_ != other.__ptr_)
221      {
222          __cxa_increment_exception_refcount(other.__ptr_);
223          __cxa_decrement_exception_refcount(__ptr_);
224          __ptr_ = other.__ptr_;
225      }
226      return *this;
227  #elif defined(__GLIBCXX__)
228      *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
229          reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
230      return *this;
231  #else
232  #   if defined(_MSC_VER) && ! defined(__clang__)
233          _LIBCPP_WARNING("exception_ptr not yet implemented")
234  #   else
235  #       warning exception_ptr not yet implemented
236  #   endif
237      printf("exception_ptr not yet implemented\n");
238      ::abort();
239  #endif
240  }
241  
nested_exception()242  nested_exception::nested_exception() _NOEXCEPT
243      : __ptr_(current_exception())
244  {
245  }
246  
247  #if !defined(__GLIBCXX__)
248  
~nested_exception()249  nested_exception::~nested_exception() _NOEXCEPT
250  {
251  }
252  
253  #endif
254  
255  _LIBCPP_NORETURN
256  void
rethrow_nested() const257  nested_exception::rethrow_nested() const
258  {
259      if (__ptr_ == nullptr)
260          terminate();
261      rethrow_exception(__ptr_);
262  }
263  
264  #if !defined(__GLIBCXX__)
265  
current_exception()266  exception_ptr current_exception() _NOEXCEPT
267  {
268  #if HAVE_DEPENDENT_EH_ABI
269      // be nicer if there was a constructor that took a ptr, then
270      // this whole function would be just:
271      //    return exception_ptr(__cxa_current_primary_exception());
272      exception_ptr ptr;
273      ptr.__ptr_ = __cxa_current_primary_exception();
274      return ptr;
275  #else
276  #   if defined(_MSC_VER) && ! defined(__clang__)
277          _LIBCPP_WARNING( "exception_ptr not yet implemented" )
278  #   else
279  #       warning exception_ptr not yet implemented
280  #   endif
281      printf("exception_ptr not yet implemented\n");
282      ::abort();
283  #endif
284  }
285  
286  #endif  // !__GLIBCXX__
287  
288  _LIBCPP_NORETURN
rethrow_exception(exception_ptr p)289  void rethrow_exception(exception_ptr p)
290  {
291  #if HAVE_DEPENDENT_EH_ABI
292      __cxa_rethrow_primary_exception(p.__ptr_);
293      // if p.__ptr_ is NULL, above returns so we terminate
294      terminate();
295  #elif defined(__GLIBCXX__)
296      rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
297  #else
298  #   if defined(_MSC_VER) && ! defined(__clang__)
299          _LIBCPP_WARNING("exception_ptr not yet implemented")
300  #   else
301  #       warning exception_ptr not yet implemented
302  #   endif
303      printf("exception_ptr not yet implemented\n");
304      ::abort();
305  #endif
306  }
307  } // std
308