From 61b302f94fd9983651bf210c8a1c0b116612022a Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Mon, 18 Mar 2019 21:50:12 +0000 Subject: [PATCH] Remove exception throwing debug mode handler support. Summary: The reason libc++ implemented a throwing debug mode handler was for ease of testing. Specifically, I thought that if a debug violation aborted, we could only test one violation per file. This made it impossible to test debug mode. Which throwing behavior we could test more! However, the throwing approach didn't work either, since there are debug violations underneath noexcept functions. This lead to the introduction of `_NOEXCEPT_DEBUG`, which was only noexcept when debug mode was off. Having thought more and having grown wiser, `_NOEXCEPT_DEBUG` was a horrible decision. It was viral, it didn't cover all the cases it needed to, and it was observable to the user -- at worst changing the behavior of their program. This patch removes the throwing debug handler, and rewrites the debug tests using 'fork-ing' style death tests. Reviewers: mclow.lists, ldionne, thomasanderson Reviewed By: ldionne Subscribers: christof, arphaman, libcxx-commits, #libc Differential Revision: https://reviews.llvm.org/D59166 llvm-svn: 356417 --- libcxx/include/__config | 16 - libcxx/include/__debug | 36 +- libcxx/include/__hash_table | 8 +- libcxx/include/iterator | 92 +-- libcxx/include/list | 12 +- libcxx/include/string | 8 +- libcxx/include/vector | 8 +- libcxx/lib/abi/CHANGELOG.TXT | 41 ++ libcxx/lib/abi/x86_64-apple-darwin.v1.abilist | 14 +- libcxx/lib/abi/x86_64-apple-darwin.v2.abilist | 15 +- .../abi/x86_64-unknown-linux-gnu.v1.abilist | 15 +- libcxx/src/debug.cpp | 59 +- .../array/array.zero/db_back.pass.cpp | 25 +- .../array/array.zero/db_front.pass.cpp | 25 +- .../array/array.zero/db_indexing.pass.cpp | 35 +- .../db_associative_container_tests.pass.cpp | 10 +- .../db_sequence_container_iterators.pass.cpp | 108 ++-- .../debug/containers/db_string.pass.cpp | 32 +- .../db_unord_container_tests.pass.cpp | 10 +- .../libcxx/debug/debug_helper_test.pass.cpp | 70 ++ ...ister.pass.cpp => debug_register.pass.cpp} | 22 +- libcxx/test/libcxx/debug/debug_throw.pass.cpp | 42 -- .../class.path/path.itr/iterator_db.pass.cpp | 34 +- .../futures.promise/set_exception.pass.cpp | 21 +- .../set_exception_at_thread_exit.pass.cpp | 19 +- libcxx/test/support/container_debug_tests.hpp | 371 +++++++++++ libcxx/test/support/debug_mode_helper.h | 605 ++++++++---------- 27 files changed, 947 insertions(+), 806 deletions(-) create mode 100644 libcxx/test/libcxx/debug/debug_helper_test.pass.cpp rename libcxx/test/libcxx/debug/{debug_throw_register.pass.cpp => debug_register.pass.cpp} (66%) delete mode 100644 libcxx/test/libcxx/debug/debug_throw.pass.cpp create mode 100644 libcxx/test/support/container_debug_tests.hpp diff --git a/libcxx/include/__config b/libcxx/include/__config index 587f38869d7e..c1770c1e5fe7 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -850,22 +850,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD # define _NOEXCEPT_(x) #endif -#if defined(_LIBCPP_DEBUG_USE_EXCEPTIONS) -# if !defined(_LIBCPP_DEBUG) -# error cannot use _LIBCPP_DEBUG_USE_EXCEPTIONS unless _LIBCPP_DEBUG is defined -# endif -# ifdef _LIBCPP_HAS_NO_NOEXCEPT -# define _NOEXCEPT_DEBUG -# define _NOEXCEPT_DEBUG_(x) -# else -# define _NOEXCEPT_DEBUG noexcept(false) -# define _NOEXCEPT_DEBUG_(x) noexcept(false) -# endif -#else -# define _NOEXCEPT_DEBUG _NOEXCEPT -# define _NOEXCEPT_DEBUG_(x) _NOEXCEPT_(x) -#endif - #ifdef _LIBCPP_HAS_NO_UNICODE_CHARS typedef unsigned short char16_t; typedef unsigned int char32_t; diff --git a/libcxx/include/__debug b/libcxx/include/__debug index 281cf6675c9b..524c5ff02847 100644 --- a/libcxx/include/__debug +++ b/libcxx/include/__debug @@ -11,6 +11,7 @@ #define _LIBCPP_DEBUG_H #include <__config> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -24,7 +25,6 @@ # include # include # include -# include #endif #if _LIBCPP_DEBUG_LEVEL >= 1 && !defined(_LIBCPP_ASSERT) @@ -49,10 +49,6 @@ #define _LIBCPP_DEBUG_MODE(...) ((void)0) #endif -#if _LIBCPP_DEBUG_LEVEL < 1 -class _LIBCPP_EXCEPTION_ABI __libcpp_debug_exception; -#endif - _LIBCPP_BEGIN_NAMESPACE_STD struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info { @@ -62,6 +58,9 @@ struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info { _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_debug_info(const char* __f, int __l, const char* __p, const char* __m) : __file_(__f), __line_(__l), __pred_(__p), __msg_(__m) {} + + _LIBCPP_FUNC_VIS std::string what() const; + const char* __file_; int __line_; const char* __pred_; @@ -79,38 +78,11 @@ extern _LIBCPP_EXPORTED_FROM_ABI __libcpp_debug_function_type __libcpp_debug_fun _LIBCPP_NORETURN _LIBCPP_FUNC_VIS void __libcpp_abort_debug_function(__libcpp_debug_info const&); -/// __libcpp_throw_debug_function - A debug handler that throws -/// an instance of __libcpp_debug_exception when called. - _LIBCPP_NORETURN _LIBCPP_FUNC_VIS -void __libcpp_throw_debug_function(__libcpp_debug_info const&); - /// __libcpp_set_debug_function - Set the debug handler to the specified /// function. _LIBCPP_FUNC_VIS bool __libcpp_set_debug_function(__libcpp_debug_function_type __func); -// Setup the throwing debug handler during dynamic initialization. -#if _LIBCPP_DEBUG_LEVEL >= 1 && defined(_LIBCPP_DEBUG_USE_EXCEPTIONS) -# if defined(_LIBCPP_NO_EXCEPTIONS) -# error _LIBCPP_DEBUG_USE_EXCEPTIONS cannot be used when exceptions are disabled. -# endif -static bool __init_dummy = __libcpp_set_debug_function(__libcpp_throw_debug_function); -#endif - -#if _LIBCPP_DEBUG_LEVEL >= 1 || defined(_LIBCPP_BUILDING_LIBRARY) -class _LIBCPP_EXCEPTION_ABI __libcpp_debug_exception : public exception { -public: - __libcpp_debug_exception() _NOEXCEPT; - explicit __libcpp_debug_exception(__libcpp_debug_info const& __i); - __libcpp_debug_exception(__libcpp_debug_exception const&); - ~__libcpp_debug_exception() _NOEXCEPT; - const char* what() const _NOEXCEPT; -private: - struct __libcpp_debug_exception_imp; - __libcpp_debug_exception_imp *__imp_; -}; -#endif - #if _LIBCPP_DEBUG_LEVEL >= 2 || defined(_LIBCPP_BUILDING_LIBRARY) struct _LIBCPP_TYPE_VIS __c_node; diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index 4409d6dc564b..c5a9db1dc419 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -1260,7 +1260,7 @@ public: void swap(__hash_table& __u) #if _LIBCPP_STD_VER <= 11 - _NOEXCEPT_DEBUG_( + _NOEXCEPT_( __is_nothrow_swappable::value && __is_nothrow_swappable::value && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value || __is_nothrow_swappable<__pointer_allocator>::value) @@ -1268,7 +1268,7 @@ public: || __is_nothrow_swappable<__node_allocator>::value) ); #else - _NOEXCEPT_DEBUG_(__is_nothrow_swappable::value && __is_nothrow_swappable::value); + _NOEXCEPT_(__is_nothrow_swappable::value && __is_nothrow_swappable::value); #endif _LIBCPP_INLINE_VISIBILITY @@ -2807,7 +2807,7 @@ template void __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u) #if _LIBCPP_STD_VER <= 11 - _NOEXCEPT_DEBUG_( + _NOEXCEPT_( __is_nothrow_swappable::value && __is_nothrow_swappable::value && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value || __is_nothrow_swappable<__pointer_allocator>::value) @@ -2815,7 +2815,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u) || __is_nothrow_swappable<__node_allocator>::value) ) #else - _NOEXCEPT_DEBUG_(__is_nothrow_swappable::value && __is_nothrow_swappable::value) + _NOEXCEPT_(__is_nothrow_swappable::value && __is_nothrow_swappable::value) #endif { _LIBCPP_ASSERT(__node_traits::propagate_on_container_swap::value || diff --git a/libcxx/include/iterator b/libcxx/include/iterator index 02cbc503c917..16c1bcb76c83 100644 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -1241,50 +1241,50 @@ template class __wrap_iter; template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; +operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; +operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; +operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; +operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; +operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; +operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; #ifndef _LIBCPP_CXX03_LANG template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG auto -operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT -> decltype(__x.base() - __y.base()); #else template _LIBCPP_INLINE_VISIBILITY typename __wrap_iter<_Iter1>::difference_type -operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; +operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; #endif template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter<_Iter> -operator+(typename __wrap_iter<_Iter>::difference_type, __wrap_iter<_Iter>) _NOEXCEPT_DEBUG; +operator+(typename __wrap_iter<_Iter>::difference_type, __wrap_iter<_Iter>) _NOEXCEPT; template _Op _LIBCPP_INLINE_VISIBILITY copy(_Ip, _Ip, _Op); template _B2 _LIBCPP_INLINE_VISIBILITY copy_backward(_B1, _B1, _B2); @@ -1328,7 +1328,7 @@ public: private: iterator_type __i; public: - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter() _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter() _NOEXCEPT #if _LIBCPP_STD_VER > 11 : __i{} #endif @@ -1339,7 +1339,7 @@ public: } template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter(const __wrap_iter<_Up>& __u, - typename enable_if::value>::type* = 0) _NOEXCEPT_DEBUG + typename enable_if::value>::type* = 0) _NOEXCEPT : __i(__u.base()) { #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -1369,7 +1369,7 @@ public: __get_db()->__erase_i(this); } #endif - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator*() const _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator*() const _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), @@ -1377,7 +1377,7 @@ public: #endif return *__i; } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG pointer operator->() const _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG pointer operator->() const _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), @@ -1385,7 +1385,7 @@ public: #endif return (pointer)_VSTD::addressof(*__i); } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), @@ -1394,10 +1394,10 @@ public: ++__i; return *this; } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator++(int) _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator++(int) _NOEXCEPT {__wrap_iter __tmp(*this); ++(*this); return __tmp;} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator--() _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator--() _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__decrementable(this), @@ -1406,11 +1406,11 @@ public: --__i; return *this; } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator--(int) _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator--(int) _NOEXCEPT {__wrap_iter __tmp(*this); --(*this); return __tmp;} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator+ (difference_type __n) const _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator+ (difference_type __n) const _NOEXCEPT {__wrap_iter __w(*this); __w += __n; return __w;} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator+=(difference_type __n) _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator+=(difference_type __n) _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__addable(this, __n), @@ -1419,11 +1419,11 @@ public: __i += __n; return *this; } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator- (difference_type __n) const _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator- (difference_type __n) const _NOEXCEPT {return *this + (-__n);} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator-=(difference_type __n) _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator-=(difference_type __n) _NOEXCEPT {*this += -__n; return *this;} - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator[](difference_type __n) const _NOEXCEPT_DEBUG + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator[](difference_type __n) const _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__subscriptable(this, __n), @@ -1432,7 +1432,7 @@ public: return __i[__n]; } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG iterator_type base() const _NOEXCEPT_DEBUG {return __i;} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG iterator_type base() const _NOEXCEPT {return __i;} private: #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -1441,7 +1441,7 @@ private: __get_db()->__insert_ic(this, __p); } #else - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter(iterator_type __x) _NOEXCEPT_DEBUG : __i(__x) {} + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter(iterator_type __x) _NOEXCEPT : __i(__x) {} #endif template friend class __wrap_iter; @@ -1452,50 +1452,50 @@ private: template _LIBCPP_CONSTEXPR_IF_NODEBUG friend bool - operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; + operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_CONSTEXPR_IF_NODEBUG friend bool - operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; + operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_CONSTEXPR_IF_NODEBUG friend bool - operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; + operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_CONSTEXPR_IF_NODEBUG friend bool - operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; + operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_CONSTEXPR_IF_NODEBUG friend bool - operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; + operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; template _LIBCPP_CONSTEXPR_IF_NODEBUG friend bool - operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; + operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; #ifndef _LIBCPP_CXX03_LANG template _LIBCPP_CONSTEXPR_IF_NODEBUG friend auto - operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG + operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT -> decltype(__x.base() - __y.base()); #else template _LIBCPP_CONSTEXPR_IF_NODEBUG friend typename __wrap_iter<_Iter1>::difference_type - operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG; + operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT; #endif template _LIBCPP_CONSTEXPR_IF_NODEBUG friend __wrap_iter<_Iter1> - operator+(typename __wrap_iter<_Iter1>::difference_type, __wrap_iter<_Iter1>) _NOEXCEPT_DEBUG; + operator+(typename __wrap_iter<_Iter1>::difference_type, __wrap_iter<_Iter1>) _NOEXCEPT; template friend _Op copy(_Ip, _Ip, _Op); template friend _B2 copy_backward(_B1, _B1, _B2); @@ -1526,7 +1526,7 @@ private: template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { return __x.base() == __y.base(); } @@ -1534,7 +1534,7 @@ operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y), @@ -1546,7 +1546,7 @@ operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { return !(__x == __y); } @@ -1554,7 +1554,7 @@ operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { return __y < __x; } @@ -1562,7 +1562,7 @@ operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { return !(__x < __y); } @@ -1570,7 +1570,7 @@ operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { return !(__y < __x); } @@ -1578,7 +1578,7 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG +operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { return !(__x == __y); } @@ -1586,7 +1586,7 @@ operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEX template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG +operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { return __y < __x; } @@ -1594,7 +1594,7 @@ operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXC template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG +operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { return !(__x < __y); } @@ -1602,7 +1602,7 @@ operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEX template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool -operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG +operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { return !(__y < __x); } @@ -1611,7 +1611,7 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEX template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG auto -operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT -> decltype(__x.base() - __y.base()) { #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -1624,7 +1624,7 @@ operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG typename __wrap_iter<_Iter1>::difference_type -operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG +operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { #if _LIBCPP_DEBUG_LEVEL >= 2 _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y), @@ -1638,7 +1638,7 @@ template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter<_Iter> operator+(typename __wrap_iter<_Iter>::difference_type __n, - __wrap_iter<_Iter> __x) _NOEXCEPT_DEBUG + __wrap_iter<_Iter> __x) _NOEXCEPT { __x += __n; return __x; diff --git a/libcxx/include/list b/libcxx/include/list index 7b59a0eb0fc5..6e878f44dd56 100644 --- a/libcxx/include/list +++ b/libcxx/include/list @@ -647,9 +647,9 @@ protected: void swap(__list_imp& __c) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT_DEBUG; + _NOEXCEPT; #else - _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value); #endif @@ -769,9 +769,9 @@ template void __list_imp<_Tp, _Alloc>::swap(__list_imp& __c) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT_DEBUG + _NOEXCEPT #else - _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value) #endif { @@ -1038,9 +1038,9 @@ public: _LIBCPP_INLINE_VISIBILITY void swap(list& __c) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT_DEBUG + _NOEXCEPT #else - _NOEXCEPT_DEBUG_(!__node_alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable<__node_allocator>::value) #endif {base::swap(__c);} diff --git a/libcxx/include/string b/libcxx/include/string index 611e3451bcf7..ab6052d7d07b 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1236,9 +1236,9 @@ public: _LIBCPP_INLINE_VISIBILITY void swap(basic_string& __str) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT_DEBUG; + _NOEXCEPT; #else - _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value); #endif @@ -3295,9 +3295,9 @@ inline void basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT_DEBUG + _NOEXCEPT #else - _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value) #endif { diff --git a/libcxx/include/vector b/libcxx/include/vector index 8413d89bb73f..e560b083afe5 100644 --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -779,9 +779,9 @@ public: void swap(vector&) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT_DEBUG; + _NOEXCEPT; #else - _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value); #endif @@ -2064,9 +2064,9 @@ template void vector<_Tp, _Allocator>::swap(vector& __x) #if _LIBCPP_STD_VER >= 14 - _NOEXCEPT_DEBUG + _NOEXCEPT #else - _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value) #endif { diff --git a/libcxx/lib/abi/CHANGELOG.TXT b/libcxx/lib/abi/CHANGELOG.TXT index 8055abaf5ca4..2e0e8a6eabd8 100644 --- a/libcxx/lib/abi/CHANGELOG.TXT +++ b/libcxx/lib/abi/CHANGELOG.TXT @@ -16,6 +16,47 @@ New entries should be added directly below the "Version" header. Version 9.0 ----------- +* rTBD - Remove exception throwing debug mode handler support. + + The reason libc++ implemented a throwing debug mode handler was for ease of testing. Specifically, + I thought that if a debug violation aborted, we could only test one violation per file. This made + it impossible to test debug mode. Which throwing behavior we could test more! + + However, the throwing approach didn't work either, since there are debug violations underneath noexcept + functions. This lead to the introduction of `_NOEXCEPT_DEBUG`, which was only noexcept when debug + mode was off. + + Having thought more and having grown wiser, `_NOEXCEPT_DEBUG` was a horrible decision. It was + viral, it didn't cover all the cases it needed to, and it was observable to the user -- at worst + changing the behavior of their program. + + This patch removes the throwing debug handler, and rewrites the debug tests using 'fork-ing' style + death tests. + + All Platforms (ignoring versioning namespaces) + ---------------------------------------------- + Symbol added: _ZNKSt3__119__libcpp_debug_info4whatEv + Symbol removed: _ZNKSt3__124__libcpp_debug_exception4whatEv + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1ERKS0_ + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1Ev + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2ERKS0_ + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2Ev + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD0Ev + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD1Ev + Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD2Ev + Symbol removed: _ZNSt3__129__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE + Symbol removed: _ZTINSt3__124__libcpp_debug_exceptionE + Symbol removed: _ZTSNSt3__124__libcpp_debug_exceptionE + Symbol removed: _ZTVNSt3__124__libcpp_debug_exceptionE + + + x86_64-apple-apple-darwin + ------------------------- + Symbol added: __ZNSt3__111__libcpp_db10__insert_cEPvPFPNS_8__c_nodeES1_S1_S3_E + Symbol removed: __ZNSt3__111__libcpp_db10__insert_cEPv + * r355367 - Fix -fsanitize=vptr badness in <__debug> This patch fixes a lifetime bug when inserting a new container into the debug database. It is diff --git a/libcxx/lib/abi/x86_64-apple-darwin.v1.abilist b/libcxx/lib/abi/x86_64-apple-darwin.v1.abilist index e861fcab8b38..67c8eb599372 100644 --- a/libcxx/lib/abi/x86_64-apple-darwin.v1.abilist +++ b/libcxx/lib/abi/x86_64-apple-darwin.v1.abilist @@ -219,6 +219,7 @@ {'is_defined': True, 'name': '__ZNKSt3__117moneypunct_bynameIwLb1EE16do_thousands_sepEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__118__time_get_storageIcE15__do_date_orderEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__118__time_get_storageIwE15__do_date_orderEv', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNKSt3__119__libcpp_debug_info4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__119__shared_weak_count13__get_deleterERKSt9type_info', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__120__codecvt_utf8_utf16IDiE10do_unshiftER11__mbstate_tPcS4_RS4_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__120__codecvt_utf8_utf16IDiE11do_encodingEv', 'type': 'FUNC'} @@ -261,7 +262,6 @@ {'is_defined': True, 'name': '__ZNKSt3__121__basic_string_commonILb1EE20__throw_out_of_rangeEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__123__match_any_but_newlineIcE6__execERNS_7__stateIcEE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__123__match_any_but_newlineIwE6__execERNS_7__stateIwEE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNKSt3__124__libcpp_debug_exception4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__15ctypeIcE10do_tolowerEPcPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__15ctypeIcE10do_tolowerEc', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__15ctypeIcE10do_toupperEPcPKc', 'type': 'FUNC'} @@ -1201,15 +1201,6 @@ {'is_defined': True, 'name': '__ZNSt3__121recursive_timed_mutexD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__121undeclare_no_pointersEPcm', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__123__libcpp_debug_functionE', 'size': 0, 'type': 'OBJECT'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC1ERKS0_', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC1Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC2ERKS0_', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC2Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionD0Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionD1Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'} @@ -1228,7 +1219,6 @@ {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIyyEEPyEEbT0_S5_T_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__127__libcpp_set_debug_functionEPFvRKNS_19__libcpp_debug_infoEE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__129__libcpp_abort_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__129__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__14cerrE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__14clogE', 'size': 0, 'type': 'OBJECT'} @@ -1654,7 +1644,6 @@ {'is_defined': True, 'name': '__ZTINSt3__120__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__120__time_get_c_storageIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__120__time_get_c_storageIwEE', 'size': 0, 'type': 'OBJECT'} -{'is_defined': True, 'name': '__ZTINSt3__124__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__15ctypeIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__15ctypeIwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__16locale5facetE', 'size': 0, 'type': 'OBJECT'} @@ -2182,7 +2171,6 @@ {'is_defined': True, 'name': '__ZTVNSt3__120__codecvt_utf8_utf16IDiEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__120__codecvt_utf8_utf16IDsEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__120__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'} -{'is_defined': True, 'name': '__ZTVNSt3__124__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__15ctypeIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__15ctypeIwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__16locale5facetE', 'size': 0, 'type': 'OBJECT'} diff --git a/libcxx/lib/abi/x86_64-apple-darwin.v2.abilist b/libcxx/lib/abi/x86_64-apple-darwin.v2.abilist index 90ea1ebb0ec6..6de64ef5decf 100644 --- a/libcxx/lib/abi/x86_64-apple-darwin.v2.abilist +++ b/libcxx/lib/abi/x86_64-apple-darwin.v2.abilist @@ -218,6 +218,7 @@ {'is_defined': True, 'name': '__ZNKSt3__217moneypunct_bynameIwLb1EE16do_thousands_sepEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__218__time_get_storageIcE15__do_date_orderEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__218__time_get_storageIwE15__do_date_orderEv', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNKSt3__219__libcpp_debug_info4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__219__shared_weak_count13__get_deleterERKSt9type_info', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__220__codecvt_utf8_utf16IDiE10do_unshiftER11__mbstate_tPcS4_RS4_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__220__codecvt_utf8_utf16IDiE11do_encodingEv', 'type': 'FUNC'} @@ -260,7 +261,6 @@ {'is_defined': True, 'name': '__ZNKSt3__221__basic_string_commonILb1EE20__throw_out_of_rangeEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__223__match_any_but_newlineIcE6__execERNS_7__stateIcEE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__223__match_any_but_newlineIwE6__execERNS_7__stateIwEE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNKSt3__224__libcpp_debug_exception4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__25ctypeIcE10do_tolowerEPcPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__25ctypeIcE10do_tolowerEc', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNKSt3__25ctypeIcE10do_toupperEPcPKc', 'type': 'FUNC'} @@ -1123,15 +1123,6 @@ {'is_defined': True, 'name': '__ZNSt3__221recursive_timed_mutexD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__221undeclare_no_pointersEPcm', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__223__libcpp_debug_functionE', 'size': 0, 'type': 'OBJECT'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC1ERKS0_', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC1Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC2ERKS0_', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC2Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionD0Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionD1Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__225notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__227__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__227__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'} @@ -1150,7 +1141,6 @@ {'is_defined': True, 'name': '__ZNSt3__227__insertion_sort_incompleteIRNS_6__lessIyyEEPyEEbT0_S5_T_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__227__libcpp_set_debug_functionEPFvRKNS_19__libcpp_debug_infoEE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__229__libcpp_abort_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '__ZNSt3__229__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__23cinE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__24cerrE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZNSt3__24clogE', 'size': 0, 'type': 'OBJECT'} @@ -1577,7 +1567,6 @@ {'is_defined': True, 'name': '__ZTINSt3__220__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__220__time_get_c_storageIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__220__time_get_c_storageIwEE', 'size': 0, 'type': 'OBJECT'} -{'is_defined': True, 'name': '__ZTINSt3__224__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__25ctypeIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__25ctypeIwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTINSt3__26locale5facetE', 'size': 0, 'type': 'OBJECT'} @@ -1867,7 +1856,6 @@ {'is_defined': True, 'name': '__ZTSNSt3__220__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTSNSt3__220__time_get_c_storageIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTSNSt3__220__time_get_c_storageIwEE', 'size': 0, 'type': 'OBJECT'} -{'is_defined': True, 'name': '__ZTSNSt3__224__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTSNSt3__25ctypeIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTSNSt3__25ctypeIwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTSNSt3__26locale5facetE', 'size': 0, 'type': 'OBJECT'} @@ -2143,7 +2131,6 @@ {'is_defined': True, 'name': '__ZTVNSt3__220__codecvt_utf8_utf16IDiEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__220__codecvt_utf8_utf16IDsEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__220__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'} -{'is_defined': True, 'name': '__ZTVNSt3__224__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__25ctypeIcEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__25ctypeIwEE', 'size': 0, 'type': 'OBJECT'} {'is_defined': True, 'name': '__ZTVNSt3__26locale5facetE', 'size': 0, 'type': 'OBJECT'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist index 3051d4cb72bc..7db6de024e24 100644 --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.v1.abilist @@ -211,6 +211,7 @@ {'is_defined': True, 'name': '_ZNKSt3__117moneypunct_bynameIwLb1EE16do_thousands_sepEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__118__time_get_storageIcE15__do_date_orderEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__118__time_get_storageIwE15__do_date_orderEv', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNKSt3__119__libcpp_debug_info4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__119__shared_weak_count13__get_deleterERKSt9type_info', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__120__codecvt_utf8_utf16IDiE10do_unshiftER11__mbstate_tPcS4_RS4_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__120__codecvt_utf8_utf16IDiE11do_encodingEv', 'type': 'FUNC'} @@ -253,7 +254,6 @@ {'is_defined': True, 'name': '_ZNKSt3__121__basic_string_commonILb1EE20__throw_out_of_rangeEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__123__match_any_but_newlineIcE6__execERNS_7__stateIcEE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__123__match_any_but_newlineIwE6__execERNS_7__stateIwEE', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNKSt3__124__libcpp_debug_exception4whatEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__15ctypeIcE10do_tolowerEPcPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__15ctypeIcE10do_tolowerEc', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNKSt3__15ctypeIcE10do_toupperEPcPKc', 'type': 'FUNC'} @@ -1114,15 +1114,6 @@ {'is_defined': True, 'name': '_ZNSt3__121recursive_timed_mutexD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__121undeclare_no_pointersEPcm', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__123__libcpp_debug_functionE', 'size': 8, 'type': 'OBJECT'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC1ERKS0_', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC1Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC2ERKS0_', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC2Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionD0Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionD1Ev', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'} @@ -1141,7 +1132,6 @@ {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIyyEEPyEEbT0_S5_T_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__127__libcpp_set_debug_functionEPFvRKNS_19__libcpp_debug_infoEE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__129__libcpp_abort_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} -{'is_defined': True, 'name': '_ZNSt3__129__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZNSt3__14cerrE', 'size': 160, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZNSt3__14clogE', 'size': 160, 'type': 'OBJECT'} @@ -1524,7 +1514,6 @@ {'is_defined': True, 'name': '_ZTINSt3__120__codecvt_utf8_utf16IwEE', 'size': 24, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__120__time_get_c_storageIcEE', 'size': 16, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__120__time_get_c_storageIwEE', 'size': 16, 'type': 'OBJECT'} -{'is_defined': True, 'name': '_ZTINSt3__124__libcpp_debug_exceptionE', 'size': 24, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__15ctypeIcEE', 'size': 56, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__15ctypeIwEE', 'size': 56, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTINSt3__16locale5facetE', 'size': 24, 'type': 'OBJECT'} @@ -1650,7 +1639,6 @@ {'is_defined': True, 'name': '_ZTSNSt3__120__codecvt_utf8_utf16IwEE', 'size': 34, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__120__time_get_c_storageIcEE', 'size': 34, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__120__time_get_c_storageIwEE', 'size': 34, 'type': 'OBJECT'} -{'is_defined': True, 'name': '_ZTSNSt3__124__libcpp_debug_exceptionE', 'size': 35, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__15ctypeIcEE', 'size': 18, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__15ctypeIwEE', 'size': 18, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTSNSt3__16locale5facetE', 'size': 22, 'type': 'OBJECT'} @@ -1762,7 +1750,6 @@ {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDiEE', 'size': 96, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDsEE', 'size': 96, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IwEE', 'size': 96, 'type': 'OBJECT'} -{'is_defined': True, 'name': '_ZTVNSt3__124__libcpp_debug_exceptionE', 'size': 40, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIcEE', 'size': 104, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIwEE', 'size': 136, 'type': 'OBJECT'} {'is_defined': True, 'name': '_ZTVNSt3__16locale5facetE', 'size': 40, 'type': 'OBJECT'} diff --git a/libcxx/src/debug.cpp b/libcxx/src/debug.cpp index 28a1f70a59b0..0f75d8ce9b62 100644 --- a/libcxx/src/debug.cpp +++ b/libcxx/src/debug.cpp @@ -17,14 +17,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD -static std::string make_what_str(__libcpp_debug_info const& info) { - string msg = info.__file_; - msg += ":" + to_string(info.__line_) + ": _LIBCPP_ASSERT '"; - msg += info.__pred_; +std::string __libcpp_debug_info::what() const { + string msg = __file_; + msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '"; + msg += __pred_; msg += "' failed. "; - msg += info.__msg_; + msg += __msg_; return msg; } +_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) { + std::fprintf(stderr, "%s\n", info.what().c_str()); + std::abort(); +} _LIBCPP_SAFE_STATIC __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function; @@ -34,51 +38,6 @@ bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) { return true; } -_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) { - std::fprintf(stderr, "%s\n", make_what_str(info).c_str()); - std::abort(); -} - -_LIBCPP_NORETURN void __libcpp_throw_debug_function(__libcpp_debug_info const& info) { -#ifndef _LIBCPP_NO_EXCEPTIONS - throw __libcpp_debug_exception(info); -#else - __libcpp_abort_debug_function(info); -#endif -} - -struct __libcpp_debug_exception::__libcpp_debug_exception_imp { - __libcpp_debug_info __info_; - std::string __what_str_; -}; - -__libcpp_debug_exception::__libcpp_debug_exception() _NOEXCEPT - : __imp_(nullptr) { -} - -__libcpp_debug_exception::__libcpp_debug_exception( - __libcpp_debug_info const& info) : __imp_(new __libcpp_debug_exception_imp) -{ - __imp_->__info_ = info; - __imp_->__what_str_ = make_what_str(info); -} -__libcpp_debug_exception::__libcpp_debug_exception( - __libcpp_debug_exception const& other) : __imp_(nullptr) { - if (other.__imp_) - __imp_ = new __libcpp_debug_exception_imp(*other.__imp_); -} - -__libcpp_debug_exception::~__libcpp_debug_exception() _NOEXCEPT { - if (__imp_) - delete __imp_; -} - -const char* __libcpp_debug_exception::what() const _NOEXCEPT { - if (__imp_) - return __imp_->__what_str_.c_str(); - return "__libcpp_debug_exception"; -} - _LIBCPP_FUNC_VIS __libcpp_db* __get_db() diff --git a/libcxx/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp index 3c3191166623..b81b25764d0d 100644 --- a/libcxx/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp +++ b/libcxx/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp @@ -5,29 +5,18 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03 -// UNSUPPORTED: libcpp-no-exceptions // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib -// test array::front() throws a debug exception. +// test array::front() raises a debug error. #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include - -template -inline bool CheckDebugThrows(Array& Arr) { - try { - Arr.back(); - } catch (std::__libcpp_debug_exception const&) { - return true; - } - return false; -} +#include "debug_mode_helper.h" int main(int, char**) { @@ -35,15 +24,15 @@ int main(int, char**) typedef std::array C; C c = {}; C const& cc = c; - assert(CheckDebugThrows(c)); - assert(CheckDebugThrows(cc)); + EXPECT_DEATH( c.back() ); + EXPECT_DEATH( cc.back() ); } { typedef std::array C; C c = {{}}; C const& cc = c; - assert(CheckDebugThrows(c)); - assert(CheckDebugThrows(cc)); + EXPECT_DEATH( c.back() ); + EXPECT_DEATH( cc.back() ); } return 0; diff --git a/libcxx/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp index 9f6f09f983d7..ec7ebbfacdce 100644 --- a/libcxx/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp +++ b/libcxx/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp @@ -5,29 +5,18 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03 -// UNSUPPORTED: libcpp-no-exceptions // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib -// test array::front() throws a debug exception. +// test array::front() raises a debug error. #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include - -template -inline bool CheckDebugThrows(Array& Arr) { - try { - Arr.front(); - } catch (std::__libcpp_debug_exception const&) { - return true; - } - return false; -} +#include "debug_mode_helper.h" int main(int, char**) { @@ -35,15 +24,15 @@ int main(int, char**) typedef std::array C; C c = {}; C const& cc = c; - assert(CheckDebugThrows(c)); - assert(CheckDebugThrows(cc)); + EXPECT_DEATH(c.front()); + EXPECT_DEATH(cc.front()); } { typedef std::array C; C c = {{}}; C const& cc = c; - assert(CheckDebugThrows(c)); - assert(CheckDebugThrows(cc)); + EXPECT_DEATH(c.front()); + EXPECT_DEATH(cc.front()); } return 0; diff --git a/libcxx/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp index 56fc326e1a7d..722dad274af2 100644 --- a/libcxx/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp +++ b/libcxx/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp @@ -5,29 +5,18 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// XFAIL:* -// UNSUPPORTED: libcpp-no-exceptions +// UNSUPPORTED: c++98, c++03 + // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib -// test array::operator[] throws a debug exception. +// test array::operator[] raises a debug error. #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include - -template -inline bool CheckDebugThrows(Array& Arr, size_t Index) { - try { - Arr[Index]; - } catch (std::__libcpp_debug_exception const&) { - return true; - } - return false; -} +#include "debug_mode_helper.h" int main(int, char**) { @@ -35,19 +24,19 @@ int main(int, char**) typedef std::array C; C c = {}; C const& cc = c; - assert(CheckDebugThrows(c, 0)); - assert(CheckDebugThrows(c, 1)); - assert(CheckDebugThrows(cc, 0)); - assert(CheckDebugThrows(cc, 1)); + EXPECT_DEATH( c[0] ); + EXPECT_DEATH( c[1] ); + EXPECT_DEATH( cc[0] ); + EXPECT_DEATH( cc[1] ); } { typedef std::array C; C c = {{}}; C const& cc = c; - assert(CheckDebugThrows(c, 0)); - assert(CheckDebugThrows(c, 1)); - assert(CheckDebugThrows(cc, 0)); - assert(CheckDebugThrows(cc, 1)); + EXPECT_DEATH( c[0] ); + EXPECT_DEATH( c[1] ); + EXPECT_DEATH( cc[0] ); + EXPECT_DEATH( cc[1] ); } return 0; diff --git a/libcxx/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp b/libcxx/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp index d6c231527dda..056d79c9006f 100644 --- a/libcxx/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp +++ b/libcxx/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp @@ -7,9 +7,8 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14 -// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr +// UNSUPPORTED: libcpp-no-if-constexpr // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib @@ -17,12 +16,12 @@ // test container debugging #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include #include #include #include +#include "container_debug_tests.hpp" #include "debug_mode_helper.h" using namespace IteratorDebugChecks; @@ -40,11 +39,6 @@ struct AssociativeContainerChecks : BasicContainerChecks { public: static void run() { Base::run(); - try { - // FIXME Add tests - } catch (...) { - assert(false && "uncaught debug exception"); - } } private: diff --git a/libcxx/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp b/libcxx/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp index d34c864ba99b..c2d1cd438cc7 100644 --- a/libcxx/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp +++ b/libcxx/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp @@ -6,11 +6,9 @@ // //===----------------------------------------------------------------------===// -// XFAIL: * // UNSUPPORTED: c++98, c++03, c++11, c++14 -// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr +// UNSUPPORTED: libcpp-no-if-constexpr // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib @@ -18,11 +16,12 @@ // test container debugging #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS + #include #include #include #include +#include "container_debug_tests.hpp" #include "debug_mode_helper.h" using namespace IteratorDebugChecks; @@ -40,11 +39,10 @@ struct SequenceContainerChecks : BasicContainerChecks { public: static void run() { Base::run(); - try { - SanityTest(); - FrontOnEmptyContainer(); + SanityTest(); + FrontOnEmptyContainer(); - if constexpr (CT != CT_ForwardList) { + if constexpr(CT != CT_ForwardList) { AssignInvalidates(); BackOnEmptyContainer(); InsertIterValue(); @@ -52,24 +50,22 @@ public: InsertIterIterIter(); EmplaceIterValue(); EraseIterIter(); - } else { - SpliceFirstElemAfter(); } - if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) { - PopBack(); - } - if constexpr (CT == CT_List || CT == CT_Deque) { - PopFront(); // FIXME: Run with forward list as well - } - if constexpr (CT == CT_List || CT == CT_ForwardList) { - RemoveFirstElem(); - } - if constexpr (CT == CT_List) { - SpliceFirstElem(); - SpliceSameContainer(); - } - } catch (...) { - assert(false && "uncaught debug exception"); + else { + SpliceFirstElemAfter(); + } + if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) { + PopBack(); + } + if constexpr (CT == CT_List || CT == CT_Deque) { + PopFront(); // FIXME: Run with forward list as well + } + if constexpr (CT == CT_List || CT == CT_ForwardList) { + RemoveFirstElem(); + } + if constexpr (CT == CT_List) { + SpliceFirstElem(); + SpliceSameContainer(); } } @@ -144,9 +140,9 @@ private: it3 = C.end(); }; auto check = [&]() { - CHECK_DEBUG_THROWS( C.erase(it1) ); - CHECK_DEBUG_THROWS( C.erase(it2) ); - CHECK_DEBUG_THROWS( C.erase(it3, C.end()) ); + EXPECT_DEATH( C.erase(it1) ); + EXPECT_DEATH( C.erase(it2) ); + EXPECT_DEATH( C.erase(it3, C.end()) ); }; reset(); C.assign(2, makeValueType(4)); @@ -173,8 +169,8 @@ private: (void)C.back(); (void)CC.back(); C.clear(); - CHECK_DEBUG_THROWS( C.back() ); - CHECK_DEBUG_THROWS( CC.back() ); + EXPECT_DEATH( C.back() ); + EXPECT_DEATH( CC.back() ); } static void FrontOnEmptyContainer() { @@ -184,8 +180,8 @@ private: (void)C.front(); (void)CC.front(); C.clear(); - CHECK_DEBUG_THROWS( C.front() ); - CHECK_DEBUG_THROWS( CC.front() ); + EXPECT_DEATH( C.front() ); + EXPECT_DEATH( CC.front() ); } static void EraseIterIter() { @@ -198,15 +194,15 @@ private: iterator it1_back = --C1.end(); assert(it1_next != it1_back); if (CT == CT_Vector) { - CHECK_DEBUG_THROWS( C1.erase(it1_next, it1) ); // bad range + EXPECT_DEATH( C1.erase(it1_next, it1) ); // bad range } C1.erase(it1, it1_after_next); - CHECK_DEBUG_THROWS( C1.erase(it1) ); - CHECK_DEBUG_THROWS( C1.erase(it1_next) ); + EXPECT_DEATH( C1.erase(it1) ); + EXPECT_DEATH( C1.erase(it1_next) ); if (CT == CT_List) { C1.erase(it1_back); } else { - CHECK_DEBUG_THROWS( C1.erase(it1_back) ); + EXPECT_DEATH( C1.erase(it1_back) ); } } @@ -216,10 +212,10 @@ private: iterator it1 = C1.end(); --it1; C1.pop_back(); - CHECK_DEBUG_THROWS( C1.erase(it1) ); + EXPECT_DEATH( C1.erase(it1) ); C1.erase(C1.begin()); assert(C1.size() == 0); - CHECK_DEBUG_THROWS( C1.pop_back() ); + EXPECT_DEATH( C1.pop_back() ); } static void PopFront() { @@ -227,10 +223,10 @@ private: Container C1 = makeContainer(2); iterator it1 = C1.begin(); C1.pop_front(); - CHECK_DEBUG_THROWS( C1.erase(it1) ); + EXPECT_DEATH( C1.erase(it1) ); C1.erase(C1.begin()); assert(C1.size() == 0); - CHECK_DEBUG_THROWS( C1.pop_front() ); + EXPECT_DEATH( C1.pop_front() ); } static void InsertIterValue() { @@ -242,8 +238,8 @@ private: Container C2 = C1; const value_type value = makeValueType(3); value_type rvalue = makeValueType(3); - CHECK_DEBUG_THROWS( C2.insert(it1, value) ); // wrong container - CHECK_DEBUG_THROWS( C2.insert(it1, std::move(rvalue)) ); // wrong container + EXPECT_DEATH( C2.insert(it1, value) ); // wrong container + EXPECT_DEATH( C2.insert(it1, std::move(rvalue)) ); // wrong container C1.insert(it1_next, value); if (CT == CT_List) { C1.insert(it1_next, value); @@ -251,10 +247,10 @@ private: C1.insert(it1_next, std::move(rvalue)); C1.insert(it1, std::move(rvalue)); } else { - CHECK_DEBUG_THROWS( C1.insert(it1_next, value) ); // invalidated iterator - CHECK_DEBUG_THROWS( C1.insert(it1, value) ); // invalidated iterator - CHECK_DEBUG_THROWS( C1.insert(it1_next, std::move(rvalue)) ); // invalidated iterator - CHECK_DEBUG_THROWS( C1.insert(it1, std::move(rvalue)) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1_next, value) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1, value) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1_next, std::move(rvalue)) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1, std::move(rvalue)) ); // invalidated iterator } } @@ -266,15 +262,15 @@ private: ++it1_next; Container C2 = C1; const value_type value = makeValueType(3); - CHECK_DEBUG_THROWS( C2.emplace(it1, value) ); // wrong container - CHECK_DEBUG_THROWS( C2.emplace(it1, makeValueType(4)) ); // wrong container + EXPECT_DEATH( C2.emplace(it1, value) ); // wrong container + EXPECT_DEATH( C2.emplace(it1, makeValueType(4)) ); // wrong container C1.emplace(it1_next, value); if (CT == CT_List) { C1.emplace(it1_next, value); C1.emplace(it1, value); } else { - CHECK_DEBUG_THROWS( C1.emplace(it1_next, value) ); // invalidated iterator - CHECK_DEBUG_THROWS( C1.emplace(it1, value) ); // invalidated iterator + EXPECT_DEATH( C1.emplace(it1_next, value) ); // invalidated iterator + EXPECT_DEATH( C1.emplace(it1, value) ); // invalidated iterator } } @@ -286,14 +282,14 @@ private: ++it1_next; Container C2 = C1; const value_type value = makeValueType(3); - CHECK_DEBUG_THROWS( C2.insert(it1, 1, value) ); // wrong container + EXPECT_DEATH( C2.insert(it1, 1, value) ); // wrong container C1.insert(it1_next, 2, value); if (CT == CT_List) { C1.insert(it1_next, 3, value); C1.insert(it1, 1, value); } else { - CHECK_DEBUG_THROWS( C1.insert(it1_next, 1, value) ); // invalidated iterator - CHECK_DEBUG_THROWS( C1.insert(it1, 1, value) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1_next, 1, value) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1, 1, value) ); // invalidated iterator } } @@ -309,14 +305,14 @@ private: makeValueType(2), makeValueType(3) }; - CHECK_DEBUG_THROWS( C2.insert(it1, V.begin(), V.end()) ); // wrong container + EXPECT_DEATH( C2.insert(it1, V.begin(), V.end()) ); // wrong container C1.insert(it1_next, V.begin(), V.end()); if (CT == CT_List) { C1.insert(it1_next, V.begin(), V.end()); C1.insert(it1, V.begin(), V.end()); } else { - CHECK_DEBUG_THROWS( C1.insert(it1_next, V.begin(), V.end()) ); // invalidated iterator - CHECK_DEBUG_THROWS( C1.insert(it1, V.begin(), V.end()) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1_next, V.begin(), V.end()) ); // invalidated iterator + EXPECT_DEATH( C1.insert(it1, V.begin(), V.end()) ); // invalidated iterator } } }; diff --git a/libcxx/test/libcxx/debug/containers/db_string.pass.cpp b/libcxx/test/libcxx/debug/containers/db_string.pass.cpp index b2812fca6196..0fb8af2baab3 100644 --- a/libcxx/test/libcxx/debug/containers/db_string.pass.cpp +++ b/libcxx/test/libcxx/debug/containers/db_string.pass.cpp @@ -7,9 +7,8 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14 -// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr +// UNSUPPORTED: libcpp-no-if-constexpr // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib @@ -17,11 +16,11 @@ // test container debugging #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include #include #include "test_macros.h" +#include "container_debug_tests.hpp" #include "debug_mode_helper.h" using namespace IteratorDebugChecks; @@ -43,14 +42,11 @@ public: static void run() { Base::run_iterator_tests(); Base::run_allocator_aware_tests(); - try { - for (int N : {3, 128}) { - FrontOnEmptyContainer(N); - BackOnEmptyContainer(N); - PopBack(N); - } - } catch (...) { - assert(false && "uncaught debug exception"); + + for (int N : {3, 128}) { + FrontOnEmptyContainer(N); + BackOnEmptyContainer(N); + PopBack(N); } } @@ -63,10 +59,10 @@ private: (void)C.back(); (void)CC.back(); C.pop_back(); - CHECK_DEBUG_THROWS( C.erase(it) ); + EXPECT_DEATH( C.erase(it) ); C.clear(); - CHECK_DEBUG_THROWS( C.back() ); - CHECK_DEBUG_THROWS( CC.back() ); + EXPECT_DEATH( C.back() ); + EXPECT_DEATH( CC.back() ); } static void FrontOnEmptyContainer(int N) { @@ -76,8 +72,8 @@ private: (void)C.front(); (void)CC.front(); C.clear(); - CHECK_DEBUG_THROWS( C.front() ); - CHECK_DEBUG_THROWS( CC.front() ); + EXPECT_DEATH( C.front() ); + EXPECT_DEATH( CC.front() ); } static void PopBack(int N) { @@ -86,10 +82,10 @@ private: iterator it1 = C1.end(); --it1; C1.pop_back(); - CHECK_DEBUG_THROWS( C1.erase(it1) ); + EXPECT_DEATH( C1.erase(it1) ); C1.erase(C1.begin(), C1.end()); assert(C1.size() == 0); - CHECK_DEBUG_THROWS( C1.pop_back() ); + EXPECT_DEATH_MATCHES(DebugInfoMatcher("string::pop_back(): string is already empty"), C1.pop_back() ); } }; diff --git a/libcxx/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp b/libcxx/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp index 8a6da08263bf..3b20e4c09b49 100644 --- a/libcxx/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp +++ b/libcxx/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp @@ -7,9 +7,8 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03, c++11, c++14 -// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr +// UNSUPPORTED: libcpp-no-if-constexpr // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib @@ -17,11 +16,11 @@ // test container debugging #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include #include #include #include +#include "container_debug_tests.hpp" #include "debug_mode_helper.h" using namespace IteratorDebugChecks; @@ -39,11 +38,6 @@ struct UnorderedContainerChecks : BasicContainerChecks { public: static void run() { Base::run(); - try { - // FIXME - } catch (...) { - assert(false && "uncaught debug exception"); - } } private: diff --git a/libcxx/test/libcxx/debug/debug_helper_test.pass.cpp b/libcxx/test/libcxx/debug/debug_helper_test.pass.cpp new file mode 100644 index 000000000000..12268e737dd1 --- /dev/null +++ b/libcxx/test/libcxx/debug/debug_helper_test.pass.cpp @@ -0,0 +1,70 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// Can't test the system lib because this test enables debug mode +// UNSUPPORTED: with_system_cxx_lib + +// MODULES_DEFINES: _LIBCPP_DEBUG=1 + +#define _LIBCPP_DEBUG 1 + +#include <__debug> +#include "debug_mode_helper.h" + + +template +inline bool TestDeathTest(const char* stmt, Func&& func, DeathTest::ResultKind ExpectResult, DebugInfoMatcher Matcher = AnyMatcher) { + DeathTest DT(Matcher); + DeathTest::ResultKind RK = DT.Run(func); + auto OnFailure = [&](std::string msg) { + std::cerr << "EXPECT_DEATH( " << stmt << " ) failed! (" << msg << ")\n\n"; + if (!DT.getChildStdErr().empty()) { + std::cerr << "---------- standard err ----------\n"; + std::cerr << DT.getChildStdErr() << "\n"; + } + if (!DT.getChildStdOut().empty()) { + std::cerr << "---------- standard out ----------\n"; + std::cerr << DT.getChildStdOut() << "\n"; + } + return false; + }; + if (RK != ExpectResult) + return OnFailure(std::string("expected result did not occur: expected ") + DeathTest::ResultKindToString(ExpectResult) + " got: " + DeathTest::ResultKindToString(RK)); + return true; +} +#define TEST_DEATH_TEST(RK, ...) assert((TestDeathTest(#__VA_ARGS__, [&]() { __VA_ARGS__; }, RK, AnyMatcher ))) + +#define TEST_DEATH_TEST_MATCHES(RK, Matcher, ...) assert((TestDeathTest(#__VA_ARGS__, [&]() { __VA_ARGS__; }, RK, Matcher))) + +void my_libcpp_assert() { + _LIBCPP_ASSERT(false, "other"); +} + +void test_no_match_found() { + DebugInfoMatcher ExpectMatch("my message"); + TEST_DEATH_TEST_MATCHES(DeathTest::RK_MatchFailure, ExpectMatch, my_libcpp_assert()); +} + +void test_did_not_die() { + TEST_DEATH_TEST(DeathTest::RK_DidNotDie, ((void)0)); +} + +void test_unknown() { + TEST_DEATH_TEST(DeathTest::RK_Unknown, std::exit(13)); +} + +int main(int, char**) +{ + test_no_match_found(); + test_did_not_die(); + test_unknown(); + return 0; +} diff --git a/libcxx/test/libcxx/debug/debug_throw_register.pass.cpp b/libcxx/test/libcxx/debug/debug_register.pass.cpp similarity index 66% rename from libcxx/test/libcxx/debug/debug_throw_register.pass.cpp rename to libcxx/test/libcxx/debug/debug_register.pass.cpp index 23b4091c3a0c..1d147af10732 100644 --- a/libcxx/test/libcxx/debug/debug_throw_register.pass.cpp +++ b/libcxx/test/libcxx/debug/debug_register.pass.cpp @@ -7,31 +7,27 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: libcpp-no-exceptions // MODULES_DEFINES: _LIBCPP_DEBUG=1 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // Can't test the system lib because this test enables debug mode // UNSUPPORTED: with_system_cxx_lib -// Test that defining _LIBCPP_DEBUG_USE_EXCEPTIONS causes _LIBCPP_ASSERT -// to throw on failure. - #define _LIBCPP_DEBUG 1 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include -#include +#include #include #include <__debug> #include +void my_debug_function(std::__libcpp_debug_info const& info) { + assert(info.__msg_ == std::string("foo")); + std::exit(0); +} + int main(int, char**) { - try { - _LIBCPP_ASSERT(false, "foo"); - assert(false); - } catch (...) {} - - return 0; + std::__libcpp_set_debug_function(&my_debug_function); + _LIBCPP_ASSERT(false, "foo"); + return 1; } diff --git a/libcxx/test/libcxx/debug/debug_throw.pass.cpp b/libcxx/test/libcxx/debug/debug_throw.pass.cpp deleted file mode 100644 index 53e8538c4a6b..000000000000 --- a/libcxx/test/libcxx/debug/debug_throw.pass.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: libcpp-no-exceptions -// MODULES_DEFINES: _LIBCPP_DEBUG=0 - -// Can't test the system lib because this test enables debug mode -// UNSUPPORTED: with_system_cxx_lib - -// Test that the default debug handler can be overridden and test the -// throwing debug handler. - -#define _LIBCPP_DEBUG 0 - -#include -#include -#include -#include <__debug> - -int main(int, char**) -{ - { - std::__libcpp_debug_function = std::__libcpp_throw_debug_function; - try { - _LIBCPP_ASSERT(false, "foo"); - } catch (std::__libcpp_debug_exception const&) {} - } - { - // test that the libc++ exception type derives from std::exception - static_assert((std::is_base_of::value), "must be an exception"); - } - - return 0; -} diff --git a/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp index 396e4ff245cb..01f07eedae4a 100644 --- a/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp +++ b/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp @@ -7,9 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++98, c++03 -// UNSUPPORTED: libcpp-no-exceptions -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // MODULES_DEFINES: _LIBCPP_DEBUG=0 // @@ -17,7 +15,6 @@ // class path #define _LIBCPP_DEBUG 0 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include "filesystem_include.hpp" #include #include @@ -25,51 +22,32 @@ #include "test_macros.h" #include "filesystem_test_helper.hpp" +#include "debug_mode_helper.h" int main(int, char**) { using namespace fs; - using ExType = std::__libcpp_debug_exception; // Test incrementing/decrementing a singular iterator { path::iterator singular; - try { - ++singular; - assert(false); - } catch (ExType const&) {} - try { - --singular; - assert(false); - } catch (ExType const&) {} + EXPECT_DEATH( ++singular ); + EXPECT_DEATH( --singular ); } // Test decrementing the begin iterator { path p("foo/bar"); auto it = p.begin(); - try { - --it; - assert(false); - } catch (ExType const&) {} ++it; ++it; - try { - ++it; - assert(false); - } catch (ExType const&) {} + EXPECT_DEATH( ++it ); } // Test incrementing the end iterator { path p("foo/bar"); auto it = p.end(); - try { - ++it; - assert(false); - } catch (ExType const&) {} + EXPECT_DEATH( ++it ); --it; --it; - try { - --it; - assert(false); - } catch (ExType const&) {} + EXPECT_DEATH( --it ); } return 0; diff --git a/libcxx/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp b/libcxx/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp index 78a8aaaa5200..a01df4b65616 100644 --- a/libcxx/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp +++ b/libcxx/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp @@ -6,11 +6,9 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: libcpp-no-exceptions // UNSUPPORTED: libcpp-has-no-threads // UNSUPPORTED: c++98, c++03 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // MODULES_DEFINES: _LIBCPP_DEBUG=0 // Can't test the system lib because this test enables debug mode @@ -24,33 +22,28 @@ // Test that a null exception_ptr is diagnosed. #define _LIBCPP_DEBUG 0 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS + #include #include #include #include +#include "debug_mode_helper.h" + int main(int, char**) { - typedef std::__libcpp_debug_exception ExType; { typedef int T; std::promise p; - try { - p.set_exception(std::exception_ptr()); - assert(false); - } catch (ExType const&) { - } + + EXPECT_DEATH( p.set_exception(std::exception_ptr()) ); } { typedef int& T; std::promise p; - try { - p.set_exception(std::exception_ptr()); - assert(false); - } catch (ExType const&) { - } + + EXPECT_DEATH( p.set_exception(std::exception_ptr()) ); } return 0; diff --git a/libcxx/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp b/libcxx/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp index baf5ba9bf34c..999c5c7cc302 100644 --- a/libcxx/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp +++ b/libcxx/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp @@ -10,7 +10,6 @@ // UNSUPPORTED: libcpp-has-no-threads // UNSUPPORTED: c++98, c++03 -// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS // MODULES_DEFINES: _LIBCPP_DEBUG=0 // Can't test the system lib because this test enables debug mode @@ -24,33 +23,27 @@ // Test that a null exception_ptr is diagnosed. #define _LIBCPP_DEBUG 0 -#define _LIBCPP_DEBUG_USE_EXCEPTIONS #include #include #include #include +#include "debug_mode_helper.h" int main(int, char**) { - typedef std::__libcpp_debug_exception ExType; { typedef int T; std::promise p; - try { - p.set_exception_at_thread_exit(std::exception_ptr()); - assert(false); - } catch (ExType const& value) { - } + + EXPECT_DEATH( p.set_exception_at_thread_exit(std::exception_ptr()) ); + } { typedef int& T; std::promise p; - try { - p.set_exception_at_thread_exit(std::exception_ptr()); - assert(false); - } catch (ExType const& value) { - } + + EXPECT_DEATH( p.set_exception_at_thread_exit(std::exception_ptr()) ); } return 0; diff --git a/libcxx/test/support/container_debug_tests.hpp b/libcxx/test/support/container_debug_tests.hpp new file mode 100644 index 000000000000..ff843eb3abf2 --- /dev/null +++ b/libcxx/test/support/container_debug_tests.hpp @@ -0,0 +1,371 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_SUPPORT_CONTAINER_DEBUG_TESTS_H +#define TEST_SUPPORT_CONTAINER_DEBUG_TESTS_H + +#include +#ifndef _LIBCPP_VERSION +#error This header may only be used for libc++ tests" +#endif + +#ifndef _LIBCPP_DEBUG +#error _LIBCPP_DEBUG must be defined before including this header +#endif + +#include <__debug> +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "debug_mode_helper.h" +#include "assert_checkpoint.h" +#include "test_allocator.h" + +// These test make use of 'if constexpr'. +#if TEST_STD_VER <= 14 +#error This header may only be used in C++17 and greater +#endif + +#ifndef __cpp_if_constexpr +#error These tests require if constexpr +#endif + + +namespace IteratorDebugChecks { + +enum ContainerType { + CT_None, + CT_String, + CT_Vector, + CT_VectorBool, + CT_List, + CT_Deque, + CT_ForwardList, + CT_Map, + CT_Set, + CT_MultiMap, + CT_MultiSet, + CT_UnorderedMap, + CT_UnorderedSet, + CT_UnorderedMultiMap, + CT_UnorderedMultiSet +}; + +constexpr bool isSequential(ContainerType CT) { + return CT_Vector >= CT && CT_ForwardList <= CT; +} + +constexpr bool isAssociative(ContainerType CT) { + return CT_Map >= CT && CT_MultiSet <= CT; +} + +constexpr bool isUnordered(ContainerType CT) { + return CT_UnorderedMap >= CT && CT_UnorderedMultiSet <= CT; +} + +constexpr bool isSet(ContainerType CT) { + return CT == CT_Set + || CT == CT_MultiSet + || CT == CT_UnorderedSet + || CT == CT_UnorderedMultiSet; +} + +constexpr bool isMap(ContainerType CT) { + return CT == CT_Map + || CT == CT_MultiMap + || CT == CT_UnorderedMap + || CT == CT_UnorderedMultiMap; +} + +constexpr bool isMulti(ContainerType CT) { + return CT == CT_MultiMap + || CT == CT_MultiSet + || CT == CT_UnorderedMultiMap + || CT == CT_UnorderedMultiSet; +} + +template +struct ContainerDebugHelper { + static_assert(std::is_constructible::value, + "must be constructible from int"); + + static ValueType makeValueType(int val = 0, int = 0) { + return ValueType(val); + } +}; + +template +struct ContainerDebugHelper { + static char makeValueType(int = 0, int = 0) { + return 'A'; + } +}; + +template +struct ContainerDebugHelper > { + using ValueType = std::pair; + static_assert(std::is_constructible::value, + "must be constructible from int"); + static_assert(std::is_constructible::value, + "must be constructible from int"); + + static ValueType makeValueType(int key = 0, int val = 0) { + return ValueType(key, val); + } +}; + +template > +struct BasicContainerChecks { + using value_type = typename Container::value_type; + using iterator = typename Container::iterator; + using const_iterator = typename Container::const_iterator; + using allocator_type = typename Container::allocator_type; + using traits = std::iterator_traits; + using category = typename traits::iterator_category; + + static_assert(std::is_same, allocator_type>::value, + "the container must use a test allocator"); + + static constexpr bool IsBiDir = + std::is_convertible::value; + + public: + static void run() { + run_iterator_tests(); + run_container_tests(); + run_allocator_aware_tests(); + } + + static void run_iterator_tests() { + try { + TestNullIterators(); + TestNullIterators(); + if constexpr (IsBiDir) { DecrementBegin(); } + IncrementEnd(); + DerefEndIterator(); + } catch (...) { + assert(false && "uncaught debug exception"); + } + } + + static void run_container_tests() { + try { + CopyInvalidatesIterators(); + MoveInvalidatesIterators(); + if constexpr (CT != CT_ForwardList) { + EraseIter(); + EraseIterIter(); + } + } catch (...) { + assert(false && "uncaught debug exception"); + } + } + + static void run_allocator_aware_tests() { + try { + SwapNonEqualAllocators(); + if constexpr (CT != CT_ForwardList ) { + // FIXME: This should work for both forward_list and string + SwapInvalidatesIterators(); + } + } catch (...) { + assert(false && "uncaught debug exception"); + } + } + + static Container makeContainer(int size, allocator_type A = allocator_type()) { + Container C(A); + if constexpr (CT == CT_ForwardList) { + for (int i = 0; i < size; ++i) + C.insert_after(C.before_begin(), Helper::makeValueType(i)); + } else { + for (int i = 0; i < size; ++i) + C.insert(C.end(), Helper::makeValueType(i)); + assert(C.size() == static_cast(size)); + } + return C; + } + + static value_type makeValueType(int value) { + return Helper::makeValueType(value); + } + + private: + // Iterator tests + template + static void TestNullIterators() { + CHECKPOINT("testing null iterator"); + Iter it; + EXPECT_DEATH( ++it ); + EXPECT_DEATH( it++ ); + EXPECT_DEATH( *it ); + if constexpr (CT != CT_VectorBool) { + EXPECT_DEATH( it.operator->() ); + } + if constexpr (IsBiDir) { + EXPECT_DEATH( --it ); + EXPECT_DEATH( it-- ); + } + } + + static void DecrementBegin() { + CHECKPOINT("testing decrement on begin"); + Container C = makeContainer(1); + iterator i = C.end(); + const_iterator ci = C.cend(); + --i; + --ci; + assert(i == C.begin()); + EXPECT_DEATH( --i ); + EXPECT_DEATH( i-- ); + EXPECT_DEATH( --ci ); + EXPECT_DEATH( ci-- ); + } + + static void IncrementEnd() { + CHECKPOINT("testing increment on end"); + Container C = makeContainer(1); + iterator i = C.begin(); + const_iterator ci = C.begin(); + ++i; + ++ci; + assert(i == C.end()); + EXPECT_DEATH( ++i ); + EXPECT_DEATH( i++ ); + EXPECT_DEATH( ++ci ); + EXPECT_DEATH( ci++ ); + } + + static void DerefEndIterator() { + CHECKPOINT("testing deref end iterator"); + Container C = makeContainer(1); + iterator i = C.begin(); + const_iterator ci = C.cbegin(); + (void)*i; (void)*ci; + if constexpr (CT != CT_VectorBool) { + i.operator->(); + ci.operator->(); + } + ++i; ++ci; + assert(i == C.end()); + EXPECT_DEATH( *i ); + EXPECT_DEATH( *ci ); + if constexpr (CT != CT_VectorBool) { + EXPECT_DEATH( i.operator->() ); + EXPECT_DEATH( ci.operator->() ); + } + } + + // Container tests + static void CopyInvalidatesIterators() { + CHECKPOINT("copy invalidates iterators"); + Container C1 = makeContainer(3); + iterator i = C1.begin(); + Container C2 = C1; + if constexpr (CT == CT_ForwardList) { + iterator i_next = i; + ++i_next; + (void)*i_next; + EXPECT_DEATH( C2.erase_after(i) ); + C1.erase_after(i); + EXPECT_DEATH( *i_next ); + } else { + EXPECT_DEATH( C2.erase(i) ); + (void)*i; + C1.erase(i); + EXPECT_DEATH( *i ); + } + } + + static void MoveInvalidatesIterators() { + CHECKPOINT("copy move invalidates iterators"); + Container C1 = makeContainer(3); + iterator i = C1.begin(); + Container C2 = std::move(C1); + (void) *i; + if constexpr (CT == CT_ForwardList) { + EXPECT_DEATH( C1.erase_after(i) ); + C2.erase_after(i); + } else { + EXPECT_DEATH( C1.erase(i) ); + C2.erase(i); + EXPECT_DEATH(*i); + } + } + + static void EraseIter() { + CHECKPOINT("testing erase invalidation"); + Container C1 = makeContainer(2); + iterator it1 = C1.begin(); + iterator it1_next = it1; + ++it1_next; + Container C2 = C1; + EXPECT_DEATH( C2.erase(it1) ); // wrong container + EXPECT_DEATH( C2.erase(C2.end()) ); // erase with end + C1.erase(it1_next); + EXPECT_DEATH( C1.erase(it1_next) ); // invalidated iterator + C1.erase(it1); + EXPECT_DEATH( C1.erase(it1) ); // invalidated iterator + } + + static void EraseIterIter() { + CHECKPOINT("testing erase iter iter invalidation"); + Container C1 = makeContainer(2); + iterator it1 = C1.begin(); + iterator it1_next = it1; + ++it1_next; + Container C2 = C1; + iterator it2 = C2.begin(); + iterator it2_next = it2; + ++it2_next; + EXPECT_DEATH( C2.erase(it1, it1_next) ); // begin from wrong container + EXPECT_DEATH( C2.erase(it1, it2_next) ); // end from wrong container + EXPECT_DEATH( C2.erase(it2, it1_next) ); // both from wrong container + C2.erase(it2, it2_next); + } + + // Allocator aware tests + static void SwapInvalidatesIterators() { + CHECKPOINT("testing swap invalidates iterators"); + Container C1 = makeContainer(3); + Container C2 = makeContainer(3); + iterator it1 = C1.begin(); + iterator it2 = C2.begin(); + swap(C1, C2); + EXPECT_DEATH( C1.erase(it1) ); + if (CT == CT_String) { + EXPECT_DEATH(C1.erase(it2)); + } else + C1.erase(it2); + //C2.erase(it1); + EXPECT_DEATH( C1.erase(it1) ); + } + + static void SwapNonEqualAllocators() { + CHECKPOINT("testing swap with non-equal allocators"); + Container C1 = makeContainer(3, allocator_type(1)); + Container C2 = makeContainer(1, allocator_type(2)); + Container C3 = makeContainer(2, allocator_type(2)); + swap(C2, C3); + EXPECT_DEATH( swap(C1, C2) ); + } + + private: + BasicContainerChecks() = delete; +}; + +} // namespace IteratorDebugChecks + +#endif // TEST_SUPPORT_CONTAINER_DEBUG_TESTS_H diff --git a/libcxx/test/support/debug_mode_helper.h b/libcxx/test/support/debug_mode_helper.h index 611b4dbb4e38..6a662d17e754 100644 --- a/libcxx/test/support/debug_mode_helper.h +++ b/libcxx/test/support/debug_mode_helper.h @@ -12,9 +12,6 @@ #ifndef _LIBCPP_DEBUG #error _LIBCPP_DEBUG must be defined before including this header #endif -#ifndef _LIBCPP_DEBUG_USE_EXCEPTIONS -#error _LIBCPP_DEBUG_USE_EXCEPTIONS must be defined before including this header -#endif #include #ifndef _LIBCPP_VERSION @@ -26,360 +23,280 @@ #include #include #include +#include +#include +#include +#include +#include #include "test_macros.h" #include "assert_checkpoint.h" #include "test_allocator.h" -// These test make use of 'if constexpr'. -#if TEST_STD_VER <= 14 -#error This header may only be used in C++17 and greater -#endif -#ifdef TEST_HAS_NO_EXCEPTIONS -#error These tests require exceptions +#if TEST_STD_VER < 11 +# error "C++11 or greater is required to use this header" #endif -#ifndef __cpp_if_constexpr -#error These tests require if constexpr -#endif +struct DebugInfoMatcher { + static const int any_line = -1; + static constexpr const char* any_file = "*"; + static constexpr const char* any_msg = "*"; -/// Assert that the specified expression throws a libc++ debug exception. -#define CHECK_DEBUG_THROWS(...) assert((CheckDebugThrows( [&]() { __VA_ARGS__; } ))) + constexpr DebugInfoMatcher() : is_empty(true), msg(any_msg), file(any_file), line(any_line) { } + constexpr DebugInfoMatcher(const char* msg, const char* file = any_file, int line = any_line) + : is_empty(false), msg(msg), file(file), line(line) {} -template -inline bool CheckDebugThrows(Func&& func) { - try { - func(); - } catch (std::__libcpp_debug_exception const&) { + bool Matches(std::__libcpp_debug_info const& got) const { + assert(!empty() && "empty matcher"); + + if (CheckLineMatches(got.__line_) && CheckFileMatches(got.__file_) && + CheckMessageMatches(got.__msg_)) + return true; + // Write to stdout because that's the file descriptor captured by the parent + // process. + std::cout << "Failed to match debug info!\n" + << ToString() << "\n" + << "VS\n" + << got.what() << "\n"; + return false; + } + + std::string ToString() const { + std::stringstream ss; + ss << "msg = \"" << msg << "\"\n" + << "line = " << (line == any_line ? "'*'" : std::to_string(line)) << "\n" + << "file = " << (file == any_file ? "'*'" : any_file) << ""; + return ss.str(); + } + + bool empty() const { return is_empty; } +private: + bool CheckLineMatches(int got_line) const { + if (line == any_line) + return true; + return got_line == line; + } + + bool CheckFileMatches(std::string_view got_file) const { + assert(!empty() && "empty matcher"); + if (file == any_file) + return true; + std::size_t found_at = got_file.find(file); + if (found_at == std::string_view::npos) + return false; + // require the match start at the beginning of the file or immediately after + // a directory separator. + if (found_at != 0) { + char last_char = got_file[found_at - 1]; + if (last_char != '/' && last_char != '\\') + return false; + } + // require the match goes until the end of the string. + return got_file.substr(found_at) == file; + } + + bool CheckMessageMatches(std::string_view got_msg) const { + assert(!empty() && "empty matcher"); + if (msg == any_msg) + return true; + std::size_t found_at = got_msg.find(msg); + if (found_at == std::string_view::npos) + return false; + // Allow any match return true; } - return false; -} - -namespace IteratorDebugChecks { - -enum ContainerType { - CT_None, - CT_String, - CT_Vector, - CT_VectorBool, - CT_List, - CT_Deque, - CT_ForwardList, - CT_Map, - CT_Set, - CT_MultiMap, - CT_MultiSet, - CT_UnorderedMap, - CT_UnorderedSet, - CT_UnorderedMultiMap, - CT_UnorderedMultiSet -}; - -constexpr bool isSequential(ContainerType CT) { - return CT_Vector >= CT && CT_ForwardList <= CT; -} - -constexpr bool isAssociative(ContainerType CT) { - return CT_Map >= CT && CT_MultiSet <= CT; -} - -constexpr bool isUnordered(ContainerType CT) { - return CT_UnorderedMap >= CT && CT_UnorderedMultiSet <= CT; -} - -constexpr bool isSet(ContainerType CT) { - return CT == CT_Set - || CT == CT_MultiSet - || CT == CT_UnorderedSet - || CT == CT_UnorderedMultiSet; -} - -constexpr bool isMap(ContainerType CT) { - return CT == CT_Map - || CT == CT_MultiMap - || CT == CT_UnorderedMap - || CT == CT_UnorderedMultiMap; -} - -constexpr bool isMulti(ContainerType CT) { - return CT == CT_MultiMap - || CT == CT_MultiSet - || CT == CT_UnorderedMultiMap - || CT == CT_UnorderedMultiSet; -} - -template -struct ContainerDebugHelper { - static_assert(std::is_constructible::value, - "must be constructible from int"); - - static ValueType makeValueType(int val = 0, int = 0) { - return ValueType(val); - } -}; - -template -struct ContainerDebugHelper { - static char makeValueType(int = 0, int = 0) { - return 'A'; - } -}; - -template -struct ContainerDebugHelper > { - using ValueType = std::pair; - static_assert(std::is_constructible::value, - "must be constructible from int"); - static_assert(std::is_constructible::value, - "must be constructible from int"); - - static ValueType makeValueType(int key = 0, int val = 0) { - return ValueType(key, val); - } -}; - -template > -struct BasicContainerChecks { - using value_type = typename Container::value_type; - using iterator = typename Container::iterator; - using const_iterator = typename Container::const_iterator; - using allocator_type = typename Container::allocator_type; - using traits = std::iterator_traits; - using category = typename traits::iterator_category; - - static_assert(std::is_same, allocator_type>::value, - "the container must use a test allocator"); - - static constexpr bool IsBiDir = - std::is_convertible::value; - -public: - static void run() { - run_iterator_tests(); - run_container_tests(); - run_allocator_aware_tests(); - } - - static void run_iterator_tests() { - try { - TestNullIterators(); - TestNullIterators(); - if constexpr (IsBiDir) { DecrementBegin(); } - IncrementEnd(); - DerefEndIterator(); - } catch (...) { - assert(false && "uncaught debug exception"); - } - } - - static void run_container_tests() { - try { - CopyInvalidatesIterators(); - MoveInvalidatesIterators(); - if constexpr (CT != CT_ForwardList) { - EraseIter(); - EraseIterIter(); - } - } catch (...) { - assert(false && "uncaught debug exception"); - } - } - - static void run_allocator_aware_tests() { - try { - SwapNonEqualAllocators(); - if constexpr (CT != CT_ForwardList ) { - // FIXME: This should work for both forward_list and string - SwapInvalidatesIterators(); - } - } catch (...) { - assert(false && "uncaught debug exception"); - } - } - - static Container makeContainer(int size, allocator_type A = allocator_type()) { - Container C(A); - if constexpr (CT == CT_ForwardList) { - for (int i = 0; i < size; ++i) - C.insert_after(C.before_begin(), Helper::makeValueType(i)); - } else { - for (int i = 0; i < size; ++i) - C.insert(C.end(), Helper::makeValueType(i)); - assert(C.size() == static_cast(size)); - } - return C; - } - - static value_type makeValueType(int value) { - return Helper::makeValueType(value); - } - private: - // Iterator tests - template - static void TestNullIterators() { - CHECKPOINT("testing null iterator"); - Iter it; - CHECK_DEBUG_THROWS( ++it ); - CHECK_DEBUG_THROWS( it++ ); - CHECK_DEBUG_THROWS( *it ); - if constexpr (CT != CT_VectorBool) { - CHECK_DEBUG_THROWS( it.operator->() ); - } - if constexpr (IsBiDir) { - CHECK_DEBUG_THROWS( --it ); - CHECK_DEBUG_THROWS( it-- ); - } - } - - static void DecrementBegin() { - CHECKPOINT("testing decrement on begin"); - Container C = makeContainer(1); - iterator i = C.end(); - const_iterator ci = C.cend(); - --i; - --ci; - assert(i == C.begin()); - CHECK_DEBUG_THROWS( --i ); - CHECK_DEBUG_THROWS( i-- ); - CHECK_DEBUG_THROWS( --ci ); - CHECK_DEBUG_THROWS( ci-- ); - } - - static void IncrementEnd() { - CHECKPOINT("testing increment on end"); - Container C = makeContainer(1); - iterator i = C.begin(); - const_iterator ci = C.begin(); - ++i; - ++ci; - assert(i == C.end()); - CHECK_DEBUG_THROWS( ++i ); - CHECK_DEBUG_THROWS( i++ ); - CHECK_DEBUG_THROWS( ++ci ); - CHECK_DEBUG_THROWS( ci++ ); - } - - static void DerefEndIterator() { - CHECKPOINT("testing deref end iterator"); - Container C = makeContainer(1); - iterator i = C.begin(); - const_iterator ci = C.cbegin(); - (void)*i; (void)*ci; - if constexpr (CT != CT_VectorBool) { - i.operator->(); - ci.operator->(); - } - ++i; ++ci; - assert(i == C.end()); - CHECK_DEBUG_THROWS( *i ); - CHECK_DEBUG_THROWS( *ci ); - if constexpr (CT != CT_VectorBool) { - CHECK_DEBUG_THROWS( i.operator->() ); - CHECK_DEBUG_THROWS( ci.operator->() ); - } - } - - // Container tests - static void CopyInvalidatesIterators() { - CHECKPOINT("copy invalidates iterators"); - Container C1 = makeContainer(3); - iterator i = C1.begin(); - Container C2 = C1; - if constexpr (CT == CT_ForwardList) { - iterator i_next = i; - ++i_next; - (void)*i_next; - CHECK_DEBUG_THROWS( C2.erase_after(i) ); - C1.erase_after(i); - CHECK_DEBUG_THROWS( *i_next ); - } else { - CHECK_DEBUG_THROWS( C2.erase(i) ); - (void)*i; - C1.erase(i); - CHECK_DEBUG_THROWS( *i ); - } - } - - static void MoveInvalidatesIterators() { - CHECKPOINT("copy move invalidates iterators"); - Container C1 = makeContainer(3); - iterator i = C1.begin(); - Container C2 = std::move(C1); - (void) *i; - if constexpr (CT == CT_ForwardList) { - CHECK_DEBUG_THROWS( C1.erase_after(i) ); - C2.erase_after(i); - } else { - CHECK_DEBUG_THROWS( C1.erase(i) ); - C2.erase(i); - CHECK_DEBUG_THROWS(*i); - } - } - - static void EraseIter() { - CHECKPOINT("testing erase invalidation"); - Container C1 = makeContainer(2); - iterator it1 = C1.begin(); - iterator it1_next = it1; - ++it1_next; - Container C2 = C1; - CHECK_DEBUG_THROWS( C2.erase(it1) ); // wrong container - CHECK_DEBUG_THROWS( C2.erase(C2.end()) ); // erase with end - C1.erase(it1_next); - CHECK_DEBUG_THROWS( C1.erase(it1_next) ); // invalidated iterator - C1.erase(it1); - CHECK_DEBUG_THROWS( C1.erase(it1) ); // invalidated iterator - } - - static void EraseIterIter() { - CHECKPOINT("testing erase iter iter invalidation"); - Container C1 = makeContainer(2); - iterator it1 = C1.begin(); - iterator it1_next = it1; - ++it1_next; - Container C2 = C1; - iterator it2 = C2.begin(); - iterator it2_next = it2; - ++it2_next; - CHECK_DEBUG_THROWS( C2.erase(it1, it1_next) ); // begin from wrong container - CHECK_DEBUG_THROWS( C2.erase(it1, it2_next) ); // end from wrong container - CHECK_DEBUG_THROWS( C2.erase(it2, it1_next) ); // both from wrong container - C2.erase(it2, it2_next); - } - - // Allocator aware tests - static void SwapInvalidatesIterators() { - CHECKPOINT("testing swap invalidates iterators"); - Container C1 = makeContainer(3); - Container C2 = makeContainer(3); - iterator it1 = C1.begin(); - iterator it2 = C2.begin(); - swap(C1, C2); - CHECK_DEBUG_THROWS( C1.erase(it1) ); - if (CT == CT_String) { - CHECK_DEBUG_THROWS(C1.erase(it2)); - } else - C1.erase(it2); - //C2.erase(it1); - CHECK_DEBUG_THROWS( C1.erase(it1) ); - } - - static void SwapNonEqualAllocators() { - CHECKPOINT("testing swap with non-equal allocators"); - Container C1 = makeContainer(3, allocator_type(1)); - Container C2 = makeContainer(1, allocator_type(2)); - Container C3 = makeContainer(2, allocator_type(2)); - swap(C2, C3); - CHECK_DEBUG_THROWS( swap(C1, C2) ); - } - -private: - BasicContainerChecks() = delete; + bool is_empty; + std::string_view msg; + std::string_view file; + int line; }; -} // namespace IteratorDebugChecks +static constexpr DebugInfoMatcher AnyMatcher(DebugInfoMatcher::any_msg); + +inline DebugInfoMatcher& GlobalMatcher() { + static DebugInfoMatcher GMatch; + return GMatch; +} + +struct DeathTest { + enum ResultKind { + RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_SetupFailure, RK_Unknown + }; + + static const char* ResultKindToString(ResultKind RK) { +#define CASE(K) case K: return #K + switch (RK) { + CASE(RK_MatchFailure); + CASE(RK_DidNotDie); + CASE(RK_SetupFailure); + CASE(RK_MatchFound); + CASE(RK_Unknown); + } + return "not a result kind"; + } + + static bool IsValidResultKind(int val) { + return val >= RK_DidNotDie && val <= RK_Unknown; + } + + TEST_NORETURN static void DeathTestDebugHandler(std::__libcpp_debug_info const& info) { + assert(!GlobalMatcher().empty()); + if (GlobalMatcher().Matches(info)) { + std::exit(RK_MatchFound); + } + std::exit(RK_MatchFailure); + } + + + DeathTest(DebugInfoMatcher const& Matcher) : matcher_(Matcher) {} + + template + ResultKind Run(Func&& f) { + int pipe_res = pipe(stdout_pipe_fd_); + assert(pipe_res != -1 && "failed to create pipe"); + pipe_res = pipe(stderr_pipe_fd_); + assert(pipe_res != -1 && "failed to create pipe"); + pid_t child_pid = fork(); + assert(child_pid != -1 && + "failed to fork a process to perform a death test"); + child_pid_ = child_pid; + if (child_pid_ == 0) { + RunForChild(std::forward(f)); + assert(false && "unreachable"); + } + return RunForParent(); + } + + int getChildExitCode() const { return exit_code_; } + std::string const& getChildStdOut() const { return stdout_from_child_; } + std::string const& getChildStdErr() const { return stderr_from_child_; } +private: + template + TEST_NORETURN void RunForChild(Func&& f) { + close(GetStdOutReadFD()); // don't need to read from the pipe in the child. + close(GetStdErrReadFD()); + auto DupFD = [](int DestFD, int TargetFD) { + int dup_result = dup2(DestFD, TargetFD); + if (dup_result == -1) + std::exit(RK_SetupFailure); + }; + DupFD(GetStdOutWriteFD(), STDOUT_FILENO); + DupFD(GetStdErrWriteFD(), STDERR_FILENO); + + GlobalMatcher() = matcher_; + std::__libcpp_set_debug_function(&DeathTestDebugHandler); + f(); + std::exit(RK_DidNotDie); + } + + static std::string ReadChildIOUntilEnd(int FD) { + std::string error_msg; + char buffer[256]; + int num_read; + do { + while ((num_read = read(FD, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error_msg += buffer; + } + } while (num_read == -1 && errno == EINTR); + return error_msg; + } + + void CaptureIOFromChild() { + close(GetStdOutWriteFD()); // no need to write from the parent process + close(GetStdErrWriteFD()); + stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD()); + stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD()); + close(GetStdOutReadFD()); + close(GetStdErrReadFD()); + } + + ResultKind RunForParent() { + CaptureIOFromChild(); + + int status_value; + pid_t result = waitpid(child_pid_, &status_value, 0); + assert(result != -1 && "there is no child process to wait for"); + + if (WIFEXITED(status_value)) { + exit_code_ = WEXITSTATUS(status_value); + if (!IsValidResultKind(exit_code_)) + return RK_Unknown; + return static_cast(exit_code_); + } + return RK_Unknown; + } + + DeathTest(DeathTest const&) = delete; + DeathTest& operator=(DeathTest const&) = delete; + + int GetStdOutReadFD() const { + return stdout_pipe_fd_[0]; + } + + int GetStdOutWriteFD() const { + return stdout_pipe_fd_[1]; + } + + int GetStdErrReadFD() const { + return stderr_pipe_fd_[0]; + } + + int GetStdErrWriteFD() const { + return stderr_pipe_fd_[1]; + } +private: + DebugInfoMatcher matcher_; + pid_t child_pid_ = -1; + int exit_code_ = -1; + int stdout_pipe_fd_[2]; + int stderr_pipe_fd_[2]; + std::string stdout_from_child_; + std::string stderr_from_child_; +}; + +template +inline bool ExpectDeath(const char* stmt, Func&& func, DebugInfoMatcher Matcher) { + DeathTest DT(Matcher); + DeathTest::ResultKind RK = DT.Run(func); + auto OnFailure = [&](const char* msg) { + std::cerr << "EXPECT_DEATH( " << stmt << " ) failed! (" << msg << ")\n\n"; + if (RK != DeathTest::RK_Unknown) { + std::cerr << "child exit code: " << DT.getChildExitCode() << "\n"; + } + if (!DT.getChildStdErr().empty()) { + std::cerr << "---------- standard err ----------\n"; + std::cerr << DT.getChildStdErr() << "\n"; + } + if (!DT.getChildStdOut().empty()) { + std::cerr << "---------- standard out ----------\n"; + std::cerr << DT.getChildStdOut() << "\n"; + } + return false; + }; + switch (RK) { + case DeathTest::RK_MatchFound: + return true; + case DeathTest::RK_SetupFailure: + return OnFailure("child failed to setup test environment"); + case DeathTest::RK_Unknown: + return OnFailure("reason unknown"); + case DeathTest::RK_DidNotDie: + return OnFailure("child did not die"); + case DeathTest::RK_MatchFailure: + return OnFailure("matcher failed"); + } +} + +template +inline bool ExpectDeath(const char* stmt, Func&& func) { + return ExpectDeath(stmt, func, AnyMatcher); +} + +/// Assert that the specified expression throws a libc++ debug exception. +#define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } ))) + +#define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher))) #endif // TEST_SUPPORT_DEBUG_MODE_HELPER_H