Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -850,22 +850,6 @@ # 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; Index: include/__debug =================================================================== --- include/__debug +++ 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 @@ _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 @@ _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; Index: include/__hash_table =================================================================== --- include/__hash_table +++ include/__hash_table @@ -1260,7 +1260,7 @@ 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 @@ || __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 @@ 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 @@ || __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 || Index: include/iterator =================================================================== --- include/iterator +++ include/iterator @@ -1241,50 +1241,50 @@ 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 @@ 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 @@ } 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 @@ __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 @@ #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 @@ #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 @@ ++__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 @@ --__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 @@ __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 @@ 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 @@ __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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; Index: include/list =================================================================== --- include/list +++ include/list @@ -647,9 +647,9 @@ 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 @@ 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 @@ _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);} Index: include/string =================================================================== --- include/string +++ include/string @@ -1236,9 +1236,9 @@ _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 @@ 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 { Index: include/vector =================================================================== --- include/vector +++ include/vector @@ -779,9 +779,9 @@ 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 @@ 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 { Index: lib/abi/CHANGELOG.TXT =================================================================== --- lib/abi/CHANGELOG.TXT +++ lib/abi/CHANGELOG.TXT @@ -16,6 +16,47 @@ 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 Index: lib/abi/x86_64-apple-darwin.v1.abilist =================================================================== --- lib/abi/x86_64-apple-darwin.v1.abilist +++ 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'} Index: lib/abi/x86_64-apple-darwin.v2.abilist =================================================================== --- lib/abi/x86_64-apple-darwin.v2.abilist +++ 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'} Index: lib/abi/x86_64-unknown-linux-gnu.v1.abilist =================================================================== --- lib/abi/x86_64-unknown-linux-gnu.v1.abilist +++ 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'} Index: src/debug.cpp =================================================================== --- src/debug.cpp +++ 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 @@ 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() Index: test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp =================================================================== --- test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp +++ 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 @@ 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; Index: test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp =================================================================== --- test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp +++ 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 @@ 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; Index: test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp =================================================================== --- test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp +++ 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 @@ 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; Index: test/libcxx/debug/containers/db_associative_container_tests.pass.cpp =================================================================== --- test/libcxx/debug/containers/db_associative_container_tests.pass.cpp +++ 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 @@ public: static void run() { Base::run(); - try { - // FIXME Add tests - } catch (...) { - assert(false && "uncaught debug exception"); - } } private: Index: test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp =================================================================== --- test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp +++ 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 @@ 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 @@ 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 @@ 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 @@ (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 @@ (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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ ++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 @@ ++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 @@ 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 } } }; Index: test/libcxx/debug/containers/db_string.pass.cpp =================================================================== --- test/libcxx/debug/containers/db_string.pass.cpp +++ 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 @@ 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 @@ (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 @@ (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 @@ 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() ); } }; Index: test/libcxx/debug/containers/db_unord_container_tests.pass.cpp =================================================================== --- test/libcxx/debug/containers/db_unord_container_tests.pass.cpp +++ 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 @@ public: static void run() { Base::run(); - try { - // FIXME - } catch (...) { - assert(false && "uncaught debug exception"); - } } private: Index: test/libcxx/debug/debug_helper_test.pass.cpp =================================================================== --- test/libcxx/debug/debug_helper_test.pass.cpp +++ 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; +} Index: test/libcxx/debug/debug_register.pass.cpp =================================================================== --- test/libcxx/debug/debug_register.pass.cpp +++ test/libcxx/debug/debug_register.pass.cpp @@ -0,0 +1,33 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// MODULES_DEFINES: _LIBCPP_DEBUG=1 + +// Can't test the system lib because this test enables debug mode +// UNSUPPORTED: with_system_cxx_lib + +#define _LIBCPP_DEBUG 1 + +#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**) +{ + std::__libcpp_set_debug_function(&my_debug_function); + _LIBCPP_ASSERT(false, "foo"); + return 1; +} Index: test/libcxx/debug/debug_throw.pass.cpp =================================================================== --- test/libcxx/debug/debug_throw.pass.cpp +++ test/libcxx/debug/debug_throw.pass.cpp @@ -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; -} Index: test/libcxx/debug/debug_throw_register.pass.cpp =================================================================== --- test/libcxx/debug/debug_throw_register.pass.cpp +++ test/libcxx/debug/debug_throw_register.pass.cpp @@ -1,37 +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=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 <__debug> -#include - -int main(int, char**) -{ - try { - _LIBCPP_ASSERT(false, "foo"); - assert(false); - } catch (...) {} - - return 0; -} Index: test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp =================================================================== --- test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp +++ 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; Index: test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp =================================================================== --- test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp +++ 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; Index: test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp =================================================================== --- test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp +++ 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; Index: test/support/container_debug_tests.hpp =================================================================== --- test/support/container_debug_tests.hpp +++ 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 Index: test/support/debug_mode_helper.h =================================================================== --- test/support/debug_mode_helper.h +++ 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 -#endif - -#ifndef __cpp_if_constexpr -#error These tests require if constexpr +#if TEST_STD_VER < 11 +# error "C++11 or greater is required to use this header" #endif -/// Assert that the specified expression throws a libc++ debug exception. -#define CHECK_DEBUG_THROWS(...) assert((CheckDebugThrows( [&]() { __VA_ARGS__; } ))) +struct DebugInfoMatcher { + static const int any_line = -1; + static constexpr const char* any_file = "*"; + static constexpr const char* any_msg = "*"; + + 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) {} + + 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; + } -template -inline bool CheckDebugThrows(Func&& func) { - try { - func(); - } catch (std::__libcpp_debug_exception const&) { - return true; + 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(); } - return false; -} -namespace IteratorDebugChecks { + 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; + } -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 + 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; + } +private: + bool is_empty; + std::string_view msg; + std::string_view file; + int line; }; -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; -} +static constexpr DebugInfoMatcher AnyMatcher(DebugInfoMatcher::any_msg); -constexpr bool isMulti(ContainerType CT) { - return CT == CT_MultiMap - || CT == CT_MultiSet - || CT == CT_UnorderedMultiMap - || CT == CT_UnorderedMultiSet; +inline DebugInfoMatcher& GlobalMatcher() { + static DebugInfoMatcher GMatch; + return GMatch; } -template -struct ContainerDebugHelper { - static_assert(std::is_constructible::value, - "must be constructible from int"); +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 ValueType makeValueType(int val = 0, int = 0) { - return ValueType(val); + static bool IsValidResultKind(int val) { + return val >= RK_DidNotDie && val <= RK_Unknown; } -}; -template -struct ContainerDebugHelper { - static char makeValueType(int = 0, int = 0) { - return 'A'; + 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); } -}; -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); - } -}; + DeathTest(DebugInfoMatcher const& Matcher) : matcher_(Matcher) {} -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"); + 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(); } - static void run_container_tests() { - try { - CopyInvalidatesIterators(); - MoveInvalidatesIterators(); - if constexpr (CT != CT_ForwardList) { - EraseIter(); - EraseIterIter(); + 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; } - } catch (...) { - assert(false && "uncaught debug exception"); - } + } while (num_read == -1 && errno == EINTR); + return error_msg; } - 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"); + 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; } - 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; - } + DeathTest(DeathTest const&) = delete; + DeathTest& operator=(DeathTest const&) = delete; - static value_type makeValueType(int value) { - return Helper::makeValueType(value); + int GetStdOutReadFD() const { + return stdout_pipe_fd_[0]; } -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-- ); - } + int GetStdOutWriteFD() const { + return stdout_pipe_fd_[1]; } - 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->() ); - } + int GetStdErrReadFD() const { + return stderr_pipe_fd_[0]; } - // 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 ); - } + 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_; +}; - 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); +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"); } +} - 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) ); - } +template +inline bool ExpectDeath(const char* stmt, Func&& func) { + return ExpectDeath(stmt, func, AnyMatcher); +} -private: - BasicContainerChecks() = delete; -}; +/// Assert that the specified expression throws a libc++ debug exception. +#define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } ))) -} // namespace IteratorDebugChecks +#define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher))) #endif // TEST_SUPPORT_DEBUG_MODE_HELPER_H