Remove exception throwing debug mode handler support.

Summary:
The reason libc++ implemented a throwing debug mode handler was for ease of testing. Specifically,
I thought that if a debug violation aborted, we could only test one violation per file. This made
it impossible to test debug mode. Which throwing behavior we could test more!

However, the throwing approach didn't work either, since there are debug violations underneath noexcept
functions. This lead to the introduction of `_NOEXCEPT_DEBUG`, which was only noexcept when debug
mode was off.

Having thought more and having grown wiser, `_NOEXCEPT_DEBUG` was a horrible decision. It was
viral, it didn't cover all the cases it needed to, and it was observable to the user -- at worst
changing the behavior of their program.

  This patch removes the throwing debug handler, and rewrites the debug tests using 'fork-ing' style
  death tests.

Reviewers: mclow.lists, ldionne, thomasanderson

Reviewed By: ldionne

Subscribers: christof, arphaman, libcxx-commits, #libc

Differential Revision: https://reviews.llvm.org/D59166

llvm-svn: 356417
This commit is contained in:
Eric Fiselier 2019-03-18 21:50:12 +00:00
parent 2d5e7adf26
commit 61b302f94f
27 changed files with 947 additions and 806 deletions

View File

@ -850,22 +850,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
# define _NOEXCEPT_(x)
#endif
#if defined(_LIBCPP_DEBUG_USE_EXCEPTIONS)
# if !defined(_LIBCPP_DEBUG)
# error cannot use _LIBCPP_DEBUG_USE_EXCEPTIONS unless _LIBCPP_DEBUG is defined
# endif
# ifdef _LIBCPP_HAS_NO_NOEXCEPT
# define _NOEXCEPT_DEBUG
# define _NOEXCEPT_DEBUG_(x)
# else
# define _NOEXCEPT_DEBUG noexcept(false)
# define _NOEXCEPT_DEBUG_(x) noexcept(false)
# endif
#else
# define _NOEXCEPT_DEBUG _NOEXCEPT
# define _NOEXCEPT_DEBUG_(x) _NOEXCEPT_(x)
#endif
#ifdef _LIBCPP_HAS_NO_UNICODE_CHARS
typedef unsigned short char16_t;
typedef unsigned int char32_t;

View File

@ -11,6 +11,7 @@
#define _LIBCPP_DEBUG_H
#include <__config>
#include <iosfwd>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
@ -24,7 +25,6 @@
# include <cstdlib>
# include <cstdio>
# include <cstddef>
# include <exception>
#endif
#if _LIBCPP_DEBUG_LEVEL >= 1 && !defined(_LIBCPP_ASSERT)
@ -49,10 +49,6 @@
#define _LIBCPP_DEBUG_MODE(...) ((void)0)
#endif
#if _LIBCPP_DEBUG_LEVEL < 1
class _LIBCPP_EXCEPTION_ABI __libcpp_debug_exception;
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info {
@ -62,6 +58,9 @@ struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info {
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
__libcpp_debug_info(const char* __f, int __l, const char* __p, const char* __m)
: __file_(__f), __line_(__l), __pred_(__p), __msg_(__m) {}
_LIBCPP_FUNC_VIS std::string what() const;
const char* __file_;
int __line_;
const char* __pred_;
@ -79,38 +78,11 @@ extern _LIBCPP_EXPORTED_FROM_ABI __libcpp_debug_function_type __libcpp_debug_fun
_LIBCPP_NORETURN _LIBCPP_FUNC_VIS
void __libcpp_abort_debug_function(__libcpp_debug_info const&);
/// __libcpp_throw_debug_function - A debug handler that throws
/// an instance of __libcpp_debug_exception when called.
_LIBCPP_NORETURN _LIBCPP_FUNC_VIS
void __libcpp_throw_debug_function(__libcpp_debug_info const&);
/// __libcpp_set_debug_function - Set the debug handler to the specified
/// function.
_LIBCPP_FUNC_VIS
bool __libcpp_set_debug_function(__libcpp_debug_function_type __func);
// Setup the throwing debug handler during dynamic initialization.
#if _LIBCPP_DEBUG_LEVEL >= 1 && defined(_LIBCPP_DEBUG_USE_EXCEPTIONS)
# if defined(_LIBCPP_NO_EXCEPTIONS)
# error _LIBCPP_DEBUG_USE_EXCEPTIONS cannot be used when exceptions are disabled.
# endif
static bool __init_dummy = __libcpp_set_debug_function(__libcpp_throw_debug_function);
#endif
#if _LIBCPP_DEBUG_LEVEL >= 1 || defined(_LIBCPP_BUILDING_LIBRARY)
class _LIBCPP_EXCEPTION_ABI __libcpp_debug_exception : public exception {
public:
__libcpp_debug_exception() _NOEXCEPT;
explicit __libcpp_debug_exception(__libcpp_debug_info const& __i);
__libcpp_debug_exception(__libcpp_debug_exception const&);
~__libcpp_debug_exception() _NOEXCEPT;
const char* what() const _NOEXCEPT;
private:
struct __libcpp_debug_exception_imp;
__libcpp_debug_exception_imp *__imp_;
};
#endif
#if _LIBCPP_DEBUG_LEVEL >= 2 || defined(_LIBCPP_BUILDING_LIBRARY)
struct _LIBCPP_TYPE_VIS __c_node;

View File

@ -1260,7 +1260,7 @@ public:
void swap(__hash_table& __u)
#if _LIBCPP_STD_VER <= 11
_NOEXCEPT_DEBUG_(
_NOEXCEPT_(
__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value
&& (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value
|| __is_nothrow_swappable<__pointer_allocator>::value)
@ -1268,7 +1268,7 @@ public:
|| __is_nothrow_swappable<__node_allocator>::value)
);
#else
_NOEXCEPT_DEBUG_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value);
_NOEXCEPT_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value);
#endif
_LIBCPP_INLINE_VISIBILITY
@ -2807,7 +2807,7 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
void
__hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
#if _LIBCPP_STD_VER <= 11
_NOEXCEPT_DEBUG_(
_NOEXCEPT_(
__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value
&& (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value
|| __is_nothrow_swappable<__pointer_allocator>::value)
@ -2815,7 +2815,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
|| __is_nothrow_swappable<__node_allocator>::value)
)
#else
_NOEXCEPT_DEBUG_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value)
_NOEXCEPT_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value)
#endif
{
_LIBCPP_ASSERT(__node_traits::propagate_on_container_swap::value ||

View File

@ -1241,50 +1241,50 @@ template <class _Iter> class __wrap_iter;
template <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter>
_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 <class _Ip, class _Op> _Op _LIBCPP_INLINE_VISIBILITY copy(_Ip, _Ip, _Op);
template <class _B1, class _B2> _B2 _LIBCPP_INLINE_VISIBILITY copy_backward(_B1, _B1, _B2);
@ -1328,7 +1328,7 @@ public:
private:
iterator_type __i;
public:
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter() _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter() _NOEXCEPT
#if _LIBCPP_STD_VER > 11
: __i{}
#endif
@ -1339,7 +1339,7 @@ public:
}
template <class _Up> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
__wrap_iter(const __wrap_iter<_Up>& __u,
typename enable_if<is_convertible<_Up, iterator_type>::value>::type* = 0) _NOEXCEPT_DEBUG
typename enable_if<is_convertible<_Up, iterator_type>::value>::type* = 0) _NOEXCEPT
: __i(__u.base())
{
#if _LIBCPP_DEBUG_LEVEL >= 2
@ -1369,7 +1369,7 @@ public:
__get_db()->__erase_i(this);
}
#endif
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator*() const _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator*() const _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
@ -1377,7 +1377,7 @@ public:
#endif
return *__i;
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG pointer operator->() const _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG pointer operator->() const _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
@ -1385,7 +1385,7 @@ public:
#endif
return (pointer)_VSTD::addressof(*__i);
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
@ -1394,10 +1394,10 @@ public:
++__i;
return *this;
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator++(int) _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator++(int) _NOEXCEPT
{__wrap_iter __tmp(*this); ++(*this); return __tmp;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator--() _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator--() _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__decrementable(this),
@ -1406,11 +1406,11 @@ public:
--__i;
return *this;
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator--(int) _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator--(int) _NOEXCEPT
{__wrap_iter __tmp(*this); --(*this); return __tmp;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator+ (difference_type __n) const _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator+ (difference_type __n) const _NOEXCEPT
{__wrap_iter __w(*this); __w += __n; return __w;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator+=(difference_type __n) _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator+=(difference_type __n) _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__addable(this, __n),
@ -1419,11 +1419,11 @@ public:
__i += __n;
return *this;
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator- (difference_type __n) const _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter operator- (difference_type __n) const _NOEXCEPT
{return *this + (-__n);}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator-=(difference_type __n) _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator-=(difference_type __n) _NOEXCEPT
{*this += -__n; return *this;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator[](difference_type __n) const _NOEXCEPT_DEBUG
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator[](difference_type __n) const _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__subscriptable(this, __n),
@ -1432,7 +1432,7 @@ public:
return __i[__n];
}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG iterator_type base() const _NOEXCEPT_DEBUG {return __i;}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG iterator_type base() const _NOEXCEPT {return __i;}
private:
#if _LIBCPP_DEBUG_LEVEL >= 2
@ -1441,7 +1441,7 @@ private:
__get_db()->__insert_ic(this, __p);
}
#else
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter(iterator_type __x) _NOEXCEPT_DEBUG : __i(__x) {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter(iterator_type __x) _NOEXCEPT : __i(__x) {}
#endif
template <class _Up> friend class __wrap_iter;
@ -1452,50 +1452,50 @@ private:
template <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1, class _Iter2>
_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 <class _Iter1>
_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 <class _Ip, class _Op> friend _Op copy(_Ip, _Ip, _Op);
template <class _B1, class _B2> friend _B2 copy_backward(_B1, _B1, _B2);
@ -1526,7 +1526,7 @@ private:
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
return __x.base() == __y.base();
}
@ -1534,7 +1534,7 @@ operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y),
@ -1546,7 +1546,7 @@ operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
return !(__x == __y);
}
@ -1554,7 +1554,7 @@ operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
return __y < __x;
}
@ -1562,7 +1562,7 @@ operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
return !(__x < __y);
}
@ -1570,7 +1570,7 @@ operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
return !(__y < __x);
}
@ -1578,7 +1578,7 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX
template <class _Iter1>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
{
return !(__x == __y);
}
@ -1586,7 +1586,7 @@ operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEX
template <class _Iter1>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
{
return __y < __x;
}
@ -1594,7 +1594,7 @@ operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXC
template <class _Iter1>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
{
return !(__x < __y);
}
@ -1602,7 +1602,7 @@ operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEX
template <class _Iter1>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
bool
operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
{
return !(__y < __x);
}
@ -1611,7 +1611,7 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEX
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
auto
operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
-> decltype(__x.base() - __y.base())
{
#if _LIBCPP_DEBUG_LEVEL >= 2
@ -1624,7 +1624,7 @@ operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC
template <class _Iter1, class _Iter2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
typename __wrap_iter<_Iter1>::difference_type
operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y),
@ -1638,7 +1638,7 @@ template <class _Iter>
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;

View File

@ -647,9 +647,9 @@ protected:
void swap(__list_imp& __c)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT_DEBUG;
_NOEXCEPT;
#else
_NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
#endif
@ -769,9 +769,9 @@ template <class _Tp, class _Alloc>
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<allocator_type>::value)
#endif
{
@ -1038,9 +1038,9 @@ public:
_LIBCPP_INLINE_VISIBILITY
void swap(list& __c)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT_DEBUG
_NOEXCEPT
#else
_NOEXCEPT_DEBUG_(!__node_alloc_traits::propagate_on_container_swap::value ||
_NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<__node_allocator>::value)
#endif
{base::swap(__c);}

View File

@ -1236,9 +1236,9 @@ public:
_LIBCPP_INLINE_VISIBILITY
void swap(basic_string& __str)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT_DEBUG;
_NOEXCEPT;
#else
_NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
#endif
@ -3295,9 +3295,9 @@ inline
void
basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT_DEBUG
_NOEXCEPT
#else
_NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value)
#endif
{

View File

@ -779,9 +779,9 @@ public:
void swap(vector&)
#if _LIBCPP_STD_VER >= 14
_NOEXCEPT_DEBUG;
_NOEXCEPT;
#else
_NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
_NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
#endif
@ -2064,9 +2064,9 @@ template <class _Tp, class _Allocator>
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<allocator_type>::value)
#endif
{

View File

@ -16,6 +16,47 @@ New entries should be added directly below the "Version" header.
Version 9.0
-----------
* rTBD - Remove exception throwing debug mode handler support.
The reason libc++ implemented a throwing debug mode handler was for ease of testing. Specifically,
I thought that if a debug violation aborted, we could only test one violation per file. This made
it impossible to test debug mode. Which throwing behavior we could test more!
However, the throwing approach didn't work either, since there are debug violations underneath noexcept
functions. This lead to the introduction of `_NOEXCEPT_DEBUG`, which was only noexcept when debug
mode was off.
Having thought more and having grown wiser, `_NOEXCEPT_DEBUG` was a horrible decision. It was
viral, it didn't cover all the cases it needed to, and it was observable to the user -- at worst
changing the behavior of their program.
This patch removes the throwing debug handler, and rewrites the debug tests using 'fork-ing' style
death tests.
All Platforms (ignoring versioning namespaces)
----------------------------------------------
Symbol added: _ZNKSt3__119__libcpp_debug_info4whatEv
Symbol removed: _ZNKSt3__124__libcpp_debug_exception4whatEv
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1ERKS0_
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1Ev
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2ERKS0_
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2Ev
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD0Ev
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD1Ev
Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD2Ev
Symbol removed: _ZNSt3__129__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE
Symbol removed: _ZTINSt3__124__libcpp_debug_exceptionE
Symbol removed: _ZTSNSt3__124__libcpp_debug_exceptionE
Symbol removed: _ZTVNSt3__124__libcpp_debug_exceptionE
x86_64-apple-apple-darwin
-------------------------
Symbol added: __ZNSt3__111__libcpp_db10__insert_cEPvPFPNS_8__c_nodeES1_S1_S3_E
Symbol removed: __ZNSt3__111__libcpp_db10__insert_cEPv
* r355367 - Fix -fsanitize=vptr badness in <__debug>
This patch fixes a lifetime bug when inserting a new container into the debug database. It is

View File

@ -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'}

View File

@ -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'}

View File

@ -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'}

View File

@ -17,14 +17,18 @@
_LIBCPP_BEGIN_NAMESPACE_STD
static std::string make_what_str(__libcpp_debug_info const& info) {
string msg = info.__file_;
msg += ":" + to_string(info.__line_) + ": _LIBCPP_ASSERT '";
msg += info.__pred_;
std::string __libcpp_debug_info::what() const {
string msg = __file_;
msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '";
msg += __pred_;
msg += "' failed. ";
msg += info.__msg_;
msg += __msg_;
return msg;
}
_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
std::fprintf(stderr, "%s\n", info.what().c_str());
std::abort();
}
_LIBCPP_SAFE_STATIC __libcpp_debug_function_type
__libcpp_debug_function = __libcpp_abort_debug_function;
@ -34,51 +38,6 @@ bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
return true;
}
_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
std::fprintf(stderr, "%s\n", make_what_str(info).c_str());
std::abort();
}
_LIBCPP_NORETURN void __libcpp_throw_debug_function(__libcpp_debug_info const& info) {
#ifndef _LIBCPP_NO_EXCEPTIONS
throw __libcpp_debug_exception(info);
#else
__libcpp_abort_debug_function(info);
#endif
}
struct __libcpp_debug_exception::__libcpp_debug_exception_imp {
__libcpp_debug_info __info_;
std::string __what_str_;
};
__libcpp_debug_exception::__libcpp_debug_exception() _NOEXCEPT
: __imp_(nullptr) {
}
__libcpp_debug_exception::__libcpp_debug_exception(
__libcpp_debug_info const& info) : __imp_(new __libcpp_debug_exception_imp)
{
__imp_->__info_ = info;
__imp_->__what_str_ = make_what_str(info);
}
__libcpp_debug_exception::__libcpp_debug_exception(
__libcpp_debug_exception const& other) : __imp_(nullptr) {
if (other.__imp_)
__imp_ = new __libcpp_debug_exception_imp(*other.__imp_);
}
__libcpp_debug_exception::~__libcpp_debug_exception() _NOEXCEPT {
if (__imp_)
delete __imp_;
}
const char* __libcpp_debug_exception::what() const _NOEXCEPT {
if (__imp_)
return __imp_->__what_str_.c_str();
return "__libcpp_debug_exception";
}
_LIBCPP_FUNC_VIS
__libcpp_db*
__get_db()

View File

@ -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<T, 0>::front() throws a debug exception.
// test array<T, 0>::front() raises a debug error.
#define _LIBCPP_DEBUG 1
#define _LIBCPP_DEBUG_USE_EXCEPTIONS
#include <array>
template <class Array>
inline bool CheckDebugThrows(Array& Arr) {
try {
Arr.back();
} catch (std::__libcpp_debug_exception const&) {
return true;
}
return false;
}
#include "debug_mode_helper.h"
int main(int, char**)
{
@ -35,15 +24,15 @@ int main(int, char**)
typedef std::array<int, 0> C;
C c = {};
C const& cc = c;
assert(CheckDebugThrows(c));
assert(CheckDebugThrows(cc));
EXPECT_DEATH( c.back() );
EXPECT_DEATH( cc.back() );
}
{
typedef std::array<const int, 0> C;
C c = {{}};
C const& cc = c;
assert(CheckDebugThrows(c));
assert(CheckDebugThrows(cc));
EXPECT_DEATH( c.back() );
EXPECT_DEATH( cc.back() );
}
return 0;

View File

@ -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<T, 0>::front() throws a debug exception.
// test array<T, 0>::front() raises a debug error.
#define _LIBCPP_DEBUG 1
#define _LIBCPP_DEBUG_USE_EXCEPTIONS
#include <array>
template <class Array>
inline bool CheckDebugThrows(Array& Arr) {
try {
Arr.front();
} catch (std::__libcpp_debug_exception const&) {
return true;
}
return false;
}
#include "debug_mode_helper.h"
int main(int, char**)
{
@ -35,15 +24,15 @@ int main(int, char**)
typedef std::array<int, 0> C;
C c = {};
C const& cc = c;
assert(CheckDebugThrows(c));
assert(CheckDebugThrows(cc));
EXPECT_DEATH(c.front());
EXPECT_DEATH(cc.front());
}
{
typedef std::array<const int, 0> C;
C c = {{}};
C const& cc = c;
assert(CheckDebugThrows(c));
assert(CheckDebugThrows(cc));
EXPECT_DEATH(c.front());
EXPECT_DEATH(cc.front());
}
return 0;

View File

@ -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<T, 0>::operator[] throws a debug exception.
// test array<T, 0>::operator[] raises a debug error.
#define _LIBCPP_DEBUG 1
#define _LIBCPP_DEBUG_USE_EXCEPTIONS
#include <array>
template <class Array>
inline bool CheckDebugThrows(Array& Arr, size_t Index) {
try {
Arr[Index];
} catch (std::__libcpp_debug_exception const&) {
return true;
}
return false;
}
#include "debug_mode_helper.h"
int main(int, char**)
{
@ -35,19 +24,19 @@ int main(int, char**)
typedef std::array<int, 0> 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<const int, 0> 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;

View File

@ -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 <map>
#include <set>
#include <utility>
#include <cassert>
#include "container_debug_tests.hpp"
#include "debug_mode_helper.h"
using namespace IteratorDebugChecks;
@ -40,11 +39,6 @@ struct AssociativeContainerChecks : BasicContainerChecks<Container, CT> {
public:
static void run() {
Base::run();
try {
// FIXME Add tests
} catch (...) {
assert(false && "uncaught debug exception");
}
}
private:

View File

@ -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 <forward_list>
#include <list>
#include <vector>
#include <deque>
#include "container_debug_tests.hpp"
#include "debug_mode_helper.h"
using namespace IteratorDebugChecks;
@ -40,11 +39,10 @@ struct SequenceContainerChecks : BasicContainerChecks<Container, CT> {
public:
static void run() {
Base::run();
try {
SanityTest();
FrontOnEmptyContainer();
SanityTest();
FrontOnEmptyContainer();
if constexpr (CT != CT_ForwardList) {
if constexpr(CT != CT_ForwardList) {
AssignInvalidates();
BackOnEmptyContainer();
InsertIterValue();
@ -52,24 +50,22 @@ public:
InsertIterIterIter();
EmplaceIterValue();
EraseIterIter();
} else {
SpliceFirstElemAfter();
}
if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) {
PopBack();
}
if constexpr (CT == CT_List || CT == CT_Deque) {
PopFront(); // FIXME: Run with forward list as well
}
if constexpr (CT == CT_List || CT == CT_ForwardList) {
RemoveFirstElem();
}
if constexpr (CT == CT_List) {
SpliceFirstElem();
SpliceSameContainer();
}
} catch (...) {
assert(false && "uncaught debug exception");
else {
SpliceFirstElemAfter();
}
if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) {
PopBack();
}
if constexpr (CT == CT_List || CT == CT_Deque) {
PopFront(); // FIXME: Run with forward list as well
}
if constexpr (CT == CT_List || CT == CT_ForwardList) {
RemoveFirstElem();
}
if constexpr (CT == CT_List) {
SpliceFirstElem();
SpliceSameContainer();
}
}
@ -144,9 +140,9 @@ private:
it3 = C.end();
};
auto check = [&]() {
CHECK_DEBUG_THROWS( C.erase(it1) );
CHECK_DEBUG_THROWS( C.erase(it2) );
CHECK_DEBUG_THROWS( C.erase(it3, C.end()) );
EXPECT_DEATH( C.erase(it1) );
EXPECT_DEATH( C.erase(it2) );
EXPECT_DEATH( C.erase(it3, C.end()) );
};
reset();
C.assign(2, makeValueType(4));
@ -173,8 +169,8 @@ private:
(void)C.back();
(void)CC.back();
C.clear();
CHECK_DEBUG_THROWS( C.back() );
CHECK_DEBUG_THROWS( CC.back() );
EXPECT_DEATH( C.back() );
EXPECT_DEATH( CC.back() );
}
static void FrontOnEmptyContainer() {
@ -184,8 +180,8 @@ private:
(void)C.front();
(void)CC.front();
C.clear();
CHECK_DEBUG_THROWS( C.front() );
CHECK_DEBUG_THROWS( CC.front() );
EXPECT_DEATH( C.front() );
EXPECT_DEATH( CC.front() );
}
static void EraseIterIter() {
@ -198,15 +194,15 @@ private:
iterator it1_back = --C1.end();
assert(it1_next != it1_back);
if (CT == CT_Vector) {
CHECK_DEBUG_THROWS( C1.erase(it1_next, it1) ); // bad range
EXPECT_DEATH( C1.erase(it1_next, it1) ); // bad range
}
C1.erase(it1, it1_after_next);
CHECK_DEBUG_THROWS( C1.erase(it1) );
CHECK_DEBUG_THROWS( C1.erase(it1_next) );
EXPECT_DEATH( C1.erase(it1) );
EXPECT_DEATH( C1.erase(it1_next) );
if (CT == CT_List) {
C1.erase(it1_back);
} else {
CHECK_DEBUG_THROWS( C1.erase(it1_back) );
EXPECT_DEATH( C1.erase(it1_back) );
}
}
@ -216,10 +212,10 @@ private:
iterator it1 = C1.end();
--it1;
C1.pop_back();
CHECK_DEBUG_THROWS( C1.erase(it1) );
EXPECT_DEATH( C1.erase(it1) );
C1.erase(C1.begin());
assert(C1.size() == 0);
CHECK_DEBUG_THROWS( C1.pop_back() );
EXPECT_DEATH( C1.pop_back() );
}
static void PopFront() {
@ -227,10 +223,10 @@ private:
Container C1 = makeContainer(2);
iterator it1 = C1.begin();
C1.pop_front();
CHECK_DEBUG_THROWS( C1.erase(it1) );
EXPECT_DEATH( C1.erase(it1) );
C1.erase(C1.begin());
assert(C1.size() == 0);
CHECK_DEBUG_THROWS( C1.pop_front() );
EXPECT_DEATH( C1.pop_front() );
}
static void InsertIterValue() {
@ -242,8 +238,8 @@ private:
Container C2 = C1;
const value_type value = makeValueType(3);
value_type rvalue = makeValueType(3);
CHECK_DEBUG_THROWS( C2.insert(it1, value) ); // wrong container
CHECK_DEBUG_THROWS( C2.insert(it1, std::move(rvalue)) ); // wrong container
EXPECT_DEATH( C2.insert(it1, value) ); // wrong container
EXPECT_DEATH( C2.insert(it1, std::move(rvalue)) ); // wrong container
C1.insert(it1_next, value);
if (CT == CT_List) {
C1.insert(it1_next, value);
@ -251,10 +247,10 @@ private:
C1.insert(it1_next, std::move(rvalue));
C1.insert(it1, std::move(rvalue));
} else {
CHECK_DEBUG_THROWS( C1.insert(it1_next, value) ); // invalidated iterator
CHECK_DEBUG_THROWS( C1.insert(it1, value) ); // invalidated iterator
CHECK_DEBUG_THROWS( C1.insert(it1_next, std::move(rvalue)) ); // invalidated iterator
CHECK_DEBUG_THROWS( C1.insert(it1, std::move(rvalue)) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1_next, value) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1, value) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1_next, std::move(rvalue)) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1, std::move(rvalue)) ); // invalidated iterator
}
}
@ -266,15 +262,15 @@ private:
++it1_next;
Container C2 = C1;
const value_type value = makeValueType(3);
CHECK_DEBUG_THROWS( C2.emplace(it1, value) ); // wrong container
CHECK_DEBUG_THROWS( C2.emplace(it1, makeValueType(4)) ); // wrong container
EXPECT_DEATH( C2.emplace(it1, value) ); // wrong container
EXPECT_DEATH( C2.emplace(it1, makeValueType(4)) ); // wrong container
C1.emplace(it1_next, value);
if (CT == CT_List) {
C1.emplace(it1_next, value);
C1.emplace(it1, value);
} else {
CHECK_DEBUG_THROWS( C1.emplace(it1_next, value) ); // invalidated iterator
CHECK_DEBUG_THROWS( C1.emplace(it1, value) ); // invalidated iterator
EXPECT_DEATH( C1.emplace(it1_next, value) ); // invalidated iterator
EXPECT_DEATH( C1.emplace(it1, value) ); // invalidated iterator
}
}
@ -286,14 +282,14 @@ private:
++it1_next;
Container C2 = C1;
const value_type value = makeValueType(3);
CHECK_DEBUG_THROWS( C2.insert(it1, 1, value) ); // wrong container
EXPECT_DEATH( C2.insert(it1, 1, value) ); // wrong container
C1.insert(it1_next, 2, value);
if (CT == CT_List) {
C1.insert(it1_next, 3, value);
C1.insert(it1, 1, value);
} else {
CHECK_DEBUG_THROWS( C1.insert(it1_next, 1, value) ); // invalidated iterator
CHECK_DEBUG_THROWS( C1.insert(it1, 1, value) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1_next, 1, value) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1, 1, value) ); // invalidated iterator
}
}
@ -309,14 +305,14 @@ private:
makeValueType(2),
makeValueType(3)
};
CHECK_DEBUG_THROWS( C2.insert(it1, V.begin(), V.end()) ); // wrong container
EXPECT_DEATH( C2.insert(it1, V.begin(), V.end()) ); // wrong container
C1.insert(it1_next, V.begin(), V.end());
if (CT == CT_List) {
C1.insert(it1_next, V.begin(), V.end());
C1.insert(it1, V.begin(), V.end());
} else {
CHECK_DEBUG_THROWS( C1.insert(it1_next, V.begin(), V.end()) ); // invalidated iterator
CHECK_DEBUG_THROWS( C1.insert(it1, V.begin(), V.end()) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1_next, V.begin(), V.end()) ); // invalidated iterator
EXPECT_DEATH( C1.insert(it1, V.begin(), V.end()) ); // invalidated iterator
}
}
};

View File

@ -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 <string>
#include <vector>
#include "test_macros.h"
#include "container_debug_tests.hpp"
#include "debug_mode_helper.h"
using namespace IteratorDebugChecks;
@ -43,14 +42,11 @@ public:
static void run() {
Base::run_iterator_tests();
Base::run_allocator_aware_tests();
try {
for (int N : {3, 128}) {
FrontOnEmptyContainer(N);
BackOnEmptyContainer(N);
PopBack(N);
}
} catch (...) {
assert(false && "uncaught debug exception");
for (int N : {3, 128}) {
FrontOnEmptyContainer(N);
BackOnEmptyContainer(N);
PopBack(N);
}
}
@ -63,10 +59,10 @@ private:
(void)C.back();
(void)CC.back();
C.pop_back();
CHECK_DEBUG_THROWS( C.erase(it) );
EXPECT_DEATH( C.erase(it) );
C.clear();
CHECK_DEBUG_THROWS( C.back() );
CHECK_DEBUG_THROWS( CC.back() );
EXPECT_DEATH( C.back() );
EXPECT_DEATH( CC.back() );
}
static void FrontOnEmptyContainer(int N) {
@ -76,8 +72,8 @@ private:
(void)C.front();
(void)CC.front();
C.clear();
CHECK_DEBUG_THROWS( C.front() );
CHECK_DEBUG_THROWS( CC.front() );
EXPECT_DEATH( C.front() );
EXPECT_DEATH( CC.front() );
}
static void PopBack(int N) {
@ -86,10 +82,10 @@ private:
iterator it1 = C1.end();
--it1;
C1.pop_back();
CHECK_DEBUG_THROWS( C1.erase(it1) );
EXPECT_DEATH( C1.erase(it1) );
C1.erase(C1.begin(), C1.end());
assert(C1.size() == 0);
CHECK_DEBUG_THROWS( C1.pop_back() );
EXPECT_DEATH_MATCHES(DebugInfoMatcher("string::pop_back(): string is already empty"), C1.pop_back() );
}
};

View File

@ -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 <unordered_map>
#include <unordered_set>
#include <utility>
#include <cassert>
#include "container_debug_tests.hpp"
#include "debug_mode_helper.h"
using namespace IteratorDebugChecks;
@ -39,11 +38,6 @@ struct UnorderedContainerChecks : BasicContainerChecks<Container, CT> {
public:
static void run() {
Base::run();
try {
// FIXME
} catch (...) {
assert(false && "uncaught debug exception");
}
}
private:

View File

@ -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 <class Func>
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;
}

View File

@ -7,31 +7,27 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: libcpp-no-exceptions
// MODULES_DEFINES: _LIBCPP_DEBUG=1
// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
// Can't test the system lib because this test enables debug mode
// UNSUPPORTED: with_system_cxx_lib
// Test that defining _LIBCPP_DEBUG_USE_EXCEPTIONS causes _LIBCPP_ASSERT
// to throw on failure.
#define _LIBCPP_DEBUG 1
#define _LIBCPP_DEBUG_USE_EXCEPTIONS
#include <cstdlib>
#include <exception>
#include <string>
#include <type_traits>
#include <__debug>
#include <cassert>
void my_debug_function(std::__libcpp_debug_info const& info) {
assert(info.__msg_ == std::string("foo"));
std::exit(0);
}
int main(int, char**)
{
try {
_LIBCPP_ASSERT(false, "foo");
assert(false);
} catch (...) {}
return 0;
std::__libcpp_set_debug_function(&my_debug_function);
_LIBCPP_ASSERT(false, "foo");
return 1;
}

View File

@ -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 <cstdlib>
#include <exception>
#include <type_traits>
#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<std::exception,
std::__libcpp_debug_exception
>::value), "must be an exception");
}
return 0;
}

View File

@ -7,9 +7,7 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
// UNSUPPORTED: libcpp-no-exceptions
// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
// MODULES_DEFINES: _LIBCPP_DEBUG=0
// <filesystem>
@ -17,7 +15,6 @@
// class path
#define _LIBCPP_DEBUG 0
#define _LIBCPP_DEBUG_USE_EXCEPTIONS
#include "filesystem_include.hpp"
#include <iterator>
#include <type_traits>
@ -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;

View File

@ -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 <future>
#include <exception>
#include <cstdlib>
#include <cassert>
#include "debug_mode_helper.h"
int main(int, char**)
{
typedef std::__libcpp_debug_exception ExType;
{
typedef int T;
std::promise<T> 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<T> p;
try {
p.set_exception(std::exception_ptr());
assert(false);
} catch (ExType const&) {
}
EXPECT_DEATH( p.set_exception(std::exception_ptr()) );
}
return 0;

View File

@ -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 <future>
#include <exception>
#include <cstdlib>
#include <cassert>
#include "debug_mode_helper.h"
int main(int, char**)
{
typedef std::__libcpp_debug_exception ExType;
{
typedef int T;
std::promise<T> 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<T> 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;

View File

@ -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 <ciso646>
#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 <utility>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <string>
#include <sstream>
#include <iostream>
#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 <class Container, class ValueType = typename Container::value_type>
struct ContainerDebugHelper {
static_assert(std::is_constructible<ValueType, int>::value,
"must be constructible from int");
static ValueType makeValueType(int val = 0, int = 0) {
return ValueType(val);
}
};
template <class Container>
struct ContainerDebugHelper<Container, char> {
static char makeValueType(int = 0, int = 0) {
return 'A';
}
};
template <class Container, class Key, class Value>
struct ContainerDebugHelper<Container, std::pair<const Key, Value> > {
using ValueType = std::pair<const Key, Value>;
static_assert(std::is_constructible<Key, int>::value,
"must be constructible from int");
static_assert(std::is_constructible<Value, int>::value,
"must be constructible from int");
static ValueType makeValueType(int key = 0, int val = 0) {
return ValueType(key, val);
}
};
template <class Container, ContainerType CT,
class Helper = ContainerDebugHelper<Container> >
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<iterator>;
using category = typename traits::iterator_category;
static_assert(std::is_same<test_allocator<value_type>, allocator_type>::value,
"the container must use a test allocator");
static constexpr bool IsBiDir =
std::is_convertible<category, std::bidirectional_iterator_tag>::value;
public:
static void run() {
run_iterator_tests();
run_container_tests();
run_allocator_aware_tests();
}
static void run_iterator_tests() {
try {
TestNullIterators<iterator>();
TestNullIterators<const_iterator>();
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<std::size_t>(size));
}
return C;
}
static value_type makeValueType(int value) {
return Helper::makeValueType(value);
}
private:
// Iterator tests
template <class Iter>
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

View File

@ -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 <ciso646>
#ifndef _LIBCPP_VERSION
@ -26,360 +23,280 @@
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <string_view>
#include <sstream>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include "test_macros.h"
#include "assert_checkpoint.h"
#include "test_allocator.h"
// These test make use of 'if constexpr'.
#if TEST_STD_VER <= 14
#error This header may only be used in C++17 and greater
#endif
#ifdef TEST_HAS_NO_EXCEPTIONS
#error These tests require exceptions
#if TEST_STD_VER < 11
# error "C++11 or greater is required to use this header"
#endif
#ifndef __cpp_if_constexpr
#error These tests require if constexpr
#endif
struct DebugInfoMatcher {
static const int any_line = -1;
static constexpr const char* any_file = "*";
static constexpr const char* any_msg = "*";
/// Assert that the specified expression throws a libc++ debug exception.
#define CHECK_DEBUG_THROWS(...) assert((CheckDebugThrows( [&]() { __VA_ARGS__; } )))
constexpr DebugInfoMatcher() : is_empty(true), msg(any_msg), file(any_file), line(any_line) { }
constexpr DebugInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
: is_empty(false), msg(msg), file(file), line(line) {}
template <class Func>
inline bool CheckDebugThrows(Func&& func) {
try {
func();
} catch (std::__libcpp_debug_exception const&) {
bool Matches(std::__libcpp_debug_info const& got) const {
assert(!empty() && "empty matcher");
if (CheckLineMatches(got.__line_) && CheckFileMatches(got.__file_) &&
CheckMessageMatches(got.__msg_))
return true;
// Write to stdout because that's the file descriptor captured by the parent
// process.
std::cout << "Failed to match debug info!\n"
<< ToString() << "\n"
<< "VS\n"
<< got.what() << "\n";
return false;
}
std::string ToString() const {
std::stringstream ss;
ss << "msg = \"" << msg << "\"\n"
<< "line = " << (line == any_line ? "'*'" : std::to_string(line)) << "\n"
<< "file = " << (file == any_file ? "'*'" : any_file) << "";
return ss.str();
}
bool empty() const { return is_empty; }
private:
bool CheckLineMatches(int got_line) const {
if (line == any_line)
return true;
return got_line == line;
}
bool CheckFileMatches(std::string_view got_file) const {
assert(!empty() && "empty matcher");
if (file == any_file)
return true;
std::size_t found_at = got_file.find(file);
if (found_at == std::string_view::npos)
return false;
// require the match start at the beginning of the file or immediately after
// a directory separator.
if (found_at != 0) {
char last_char = got_file[found_at - 1];
if (last_char != '/' && last_char != '\\')
return false;
}
// require the match goes until the end of the string.
return got_file.substr(found_at) == file;
}
bool CheckMessageMatches(std::string_view got_msg) const {
assert(!empty() && "empty matcher");
if (msg == any_msg)
return true;
std::size_t found_at = got_msg.find(msg);
if (found_at == std::string_view::npos)
return false;
// Allow any match
return true;
}
return false;
}
namespace IteratorDebugChecks {
enum ContainerType {
CT_None,
CT_String,
CT_Vector,
CT_VectorBool,
CT_List,
CT_Deque,
CT_ForwardList,
CT_Map,
CT_Set,
CT_MultiMap,
CT_MultiSet,
CT_UnorderedMap,
CT_UnorderedSet,
CT_UnorderedMultiMap,
CT_UnorderedMultiSet
};
constexpr bool isSequential(ContainerType CT) {
return CT_Vector >= CT && CT_ForwardList <= CT;
}
constexpr bool isAssociative(ContainerType CT) {
return CT_Map >= CT && CT_MultiSet <= CT;
}
constexpr bool isUnordered(ContainerType CT) {
return CT_UnorderedMap >= CT && CT_UnorderedMultiSet <= CT;
}
constexpr bool isSet(ContainerType CT) {
return CT == CT_Set
|| CT == CT_MultiSet
|| CT == CT_UnorderedSet
|| CT == CT_UnorderedMultiSet;
}
constexpr bool isMap(ContainerType CT) {
return CT == CT_Map
|| CT == CT_MultiMap
|| CT == CT_UnorderedMap
|| CT == CT_UnorderedMultiMap;
}
constexpr bool isMulti(ContainerType CT) {
return CT == CT_MultiMap
|| CT == CT_MultiSet
|| CT == CT_UnorderedMultiMap
|| CT == CT_UnorderedMultiSet;
}
template <class Container, class ValueType = typename Container::value_type>
struct ContainerDebugHelper {
static_assert(std::is_constructible<ValueType, int>::value,
"must be constructible from int");
static ValueType makeValueType(int val = 0, int = 0) {
return ValueType(val);
}
};
template <class Container>
struct ContainerDebugHelper<Container, char> {
static char makeValueType(int = 0, int = 0) {
return 'A';
}
};
template <class Container, class Key, class Value>
struct ContainerDebugHelper<Container, std::pair<const Key, Value> > {
using ValueType = std::pair<const Key, Value>;
static_assert(std::is_constructible<Key, int>::value,
"must be constructible from int");
static_assert(std::is_constructible<Value, int>::value,
"must be constructible from int");
static ValueType makeValueType(int key = 0, int val = 0) {
return ValueType(key, val);
}
};
template <class Container, ContainerType CT,
class Helper = ContainerDebugHelper<Container> >
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<iterator>;
using category = typename traits::iterator_category;
static_assert(std::is_same<test_allocator<value_type>, allocator_type>::value,
"the container must use a test allocator");
static constexpr bool IsBiDir =
std::is_convertible<category, std::bidirectional_iterator_tag>::value;
public:
static void run() {
run_iterator_tests();
run_container_tests();
run_allocator_aware_tests();
}
static void run_iterator_tests() {
try {
TestNullIterators<iterator>();
TestNullIterators<const_iterator>();
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<std::size_t>(size));
}
return C;
}
static value_type makeValueType(int value) {
return Helper::makeValueType(value);
}
private:
// Iterator tests
template <class Iter>
static void TestNullIterators() {
CHECKPOINT("testing null iterator");
Iter it;
CHECK_DEBUG_THROWS( ++it );
CHECK_DEBUG_THROWS( it++ );
CHECK_DEBUG_THROWS( *it );
if constexpr (CT != CT_VectorBool) {
CHECK_DEBUG_THROWS( it.operator->() );
}
if constexpr (IsBiDir) {
CHECK_DEBUG_THROWS( --it );
CHECK_DEBUG_THROWS( it-- );
}
}
static void DecrementBegin() {
CHECKPOINT("testing decrement on begin");
Container C = makeContainer(1);
iterator i = C.end();
const_iterator ci = C.cend();
--i;
--ci;
assert(i == C.begin());
CHECK_DEBUG_THROWS( --i );
CHECK_DEBUG_THROWS( i-- );
CHECK_DEBUG_THROWS( --ci );
CHECK_DEBUG_THROWS( ci-- );
}
static void IncrementEnd() {
CHECKPOINT("testing increment on end");
Container C = makeContainer(1);
iterator i = C.begin();
const_iterator ci = C.begin();
++i;
++ci;
assert(i == C.end());
CHECK_DEBUG_THROWS( ++i );
CHECK_DEBUG_THROWS( i++ );
CHECK_DEBUG_THROWS( ++ci );
CHECK_DEBUG_THROWS( ci++ );
}
static void DerefEndIterator() {
CHECKPOINT("testing deref end iterator");
Container C = makeContainer(1);
iterator i = C.begin();
const_iterator ci = C.cbegin();
(void)*i; (void)*ci;
if constexpr (CT != CT_VectorBool) {
i.operator->();
ci.operator->();
}
++i; ++ci;
assert(i == C.end());
CHECK_DEBUG_THROWS( *i );
CHECK_DEBUG_THROWS( *ci );
if constexpr (CT != CT_VectorBool) {
CHECK_DEBUG_THROWS( i.operator->() );
CHECK_DEBUG_THROWS( ci.operator->() );
}
}
// Container tests
static void CopyInvalidatesIterators() {
CHECKPOINT("copy invalidates iterators");
Container C1 = makeContainer(3);
iterator i = C1.begin();
Container C2 = C1;
if constexpr (CT == CT_ForwardList) {
iterator i_next = i;
++i_next;
(void)*i_next;
CHECK_DEBUG_THROWS( C2.erase_after(i) );
C1.erase_after(i);
CHECK_DEBUG_THROWS( *i_next );
} else {
CHECK_DEBUG_THROWS( C2.erase(i) );
(void)*i;
C1.erase(i);
CHECK_DEBUG_THROWS( *i );
}
}
static void MoveInvalidatesIterators() {
CHECKPOINT("copy move invalidates iterators");
Container C1 = makeContainer(3);
iterator i = C1.begin();
Container C2 = std::move(C1);
(void) *i;
if constexpr (CT == CT_ForwardList) {
CHECK_DEBUG_THROWS( C1.erase_after(i) );
C2.erase_after(i);
} else {
CHECK_DEBUG_THROWS( C1.erase(i) );
C2.erase(i);
CHECK_DEBUG_THROWS(*i);
}
}
static void EraseIter() {
CHECKPOINT("testing erase invalidation");
Container C1 = makeContainer(2);
iterator it1 = C1.begin();
iterator it1_next = it1;
++it1_next;
Container C2 = C1;
CHECK_DEBUG_THROWS( C2.erase(it1) ); // wrong container
CHECK_DEBUG_THROWS( C2.erase(C2.end()) ); // erase with end
C1.erase(it1_next);
CHECK_DEBUG_THROWS( C1.erase(it1_next) ); // invalidated iterator
C1.erase(it1);
CHECK_DEBUG_THROWS( C1.erase(it1) ); // invalidated iterator
}
static void EraseIterIter() {
CHECKPOINT("testing erase iter iter invalidation");
Container C1 = makeContainer(2);
iterator it1 = C1.begin();
iterator it1_next = it1;
++it1_next;
Container C2 = C1;
iterator it2 = C2.begin();
iterator it2_next = it2;
++it2_next;
CHECK_DEBUG_THROWS( C2.erase(it1, it1_next) ); // begin from wrong container
CHECK_DEBUG_THROWS( C2.erase(it1, it2_next) ); // end from wrong container
CHECK_DEBUG_THROWS( C2.erase(it2, it1_next) ); // both from wrong container
C2.erase(it2, it2_next);
}
// Allocator aware tests
static void SwapInvalidatesIterators() {
CHECKPOINT("testing swap invalidates iterators");
Container C1 = makeContainer(3);
Container C2 = makeContainer(3);
iterator it1 = C1.begin();
iterator it2 = C2.begin();
swap(C1, C2);
CHECK_DEBUG_THROWS( C1.erase(it1) );
if (CT == CT_String) {
CHECK_DEBUG_THROWS(C1.erase(it2));
} else
C1.erase(it2);
//C2.erase(it1);
CHECK_DEBUG_THROWS( C1.erase(it1) );
}
static void SwapNonEqualAllocators() {
CHECKPOINT("testing swap with non-equal allocators");
Container C1 = makeContainer(3, allocator_type(1));
Container C2 = makeContainer(1, allocator_type(2));
Container C3 = makeContainer(2, allocator_type(2));
swap(C2, C3);
CHECK_DEBUG_THROWS( swap(C1, C2) );
}
private:
BasicContainerChecks() = delete;
bool is_empty;
std::string_view msg;
std::string_view file;
int line;
};
} // namespace IteratorDebugChecks
static constexpr DebugInfoMatcher AnyMatcher(DebugInfoMatcher::any_msg);
inline DebugInfoMatcher& GlobalMatcher() {
static DebugInfoMatcher GMatch;
return GMatch;
}
struct DeathTest {
enum ResultKind {
RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_SetupFailure, RK_Unknown
};
static const char* ResultKindToString(ResultKind RK) {
#define CASE(K) case K: return #K
switch (RK) {
CASE(RK_MatchFailure);
CASE(RK_DidNotDie);
CASE(RK_SetupFailure);
CASE(RK_MatchFound);
CASE(RK_Unknown);
}
return "not a result kind";
}
static bool IsValidResultKind(int val) {
return val >= RK_DidNotDie && val <= RK_Unknown;
}
TEST_NORETURN static void DeathTestDebugHandler(std::__libcpp_debug_info const& info) {
assert(!GlobalMatcher().empty());
if (GlobalMatcher().Matches(info)) {
std::exit(RK_MatchFound);
}
std::exit(RK_MatchFailure);
}
DeathTest(DebugInfoMatcher const& Matcher) : matcher_(Matcher) {}
template <class Func>
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<Func>(f));
assert(false && "unreachable");
}
return RunForParent();
}
int getChildExitCode() const { return exit_code_; }
std::string const& getChildStdOut() const { return stdout_from_child_; }
std::string const& getChildStdErr() const { return stderr_from_child_; }
private:
template <class Func>
TEST_NORETURN void RunForChild(Func&& f) {
close(GetStdOutReadFD()); // don't need to read from the pipe in the child.
close(GetStdErrReadFD());
auto DupFD = [](int DestFD, int TargetFD) {
int dup_result = dup2(DestFD, TargetFD);
if (dup_result == -1)
std::exit(RK_SetupFailure);
};
DupFD(GetStdOutWriteFD(), STDOUT_FILENO);
DupFD(GetStdErrWriteFD(), STDERR_FILENO);
GlobalMatcher() = matcher_;
std::__libcpp_set_debug_function(&DeathTestDebugHandler);
f();
std::exit(RK_DidNotDie);
}
static std::string ReadChildIOUntilEnd(int FD) {
std::string error_msg;
char buffer[256];
int num_read;
do {
while ((num_read = read(FD, buffer, 255)) > 0) {
buffer[num_read] = '\0';
error_msg += buffer;
}
} while (num_read == -1 && errno == EINTR);
return error_msg;
}
void CaptureIOFromChild() {
close(GetStdOutWriteFD()); // no need to write from the parent process
close(GetStdErrWriteFD());
stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD());
stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD());
close(GetStdOutReadFD());
close(GetStdErrReadFD());
}
ResultKind RunForParent() {
CaptureIOFromChild();
int status_value;
pid_t result = waitpid(child_pid_, &status_value, 0);
assert(result != -1 && "there is no child process to wait for");
if (WIFEXITED(status_value)) {
exit_code_ = WEXITSTATUS(status_value);
if (!IsValidResultKind(exit_code_))
return RK_Unknown;
return static_cast<ResultKind>(exit_code_);
}
return RK_Unknown;
}
DeathTest(DeathTest const&) = delete;
DeathTest& operator=(DeathTest const&) = delete;
int GetStdOutReadFD() const {
return stdout_pipe_fd_[0];
}
int GetStdOutWriteFD() const {
return stdout_pipe_fd_[1];
}
int GetStdErrReadFD() const {
return stderr_pipe_fd_[0];
}
int GetStdErrWriteFD() const {
return stderr_pipe_fd_[1];
}
private:
DebugInfoMatcher matcher_;
pid_t child_pid_ = -1;
int exit_code_ = -1;
int stdout_pipe_fd_[2];
int stderr_pipe_fd_[2];
std::string stdout_from_child_;
std::string stderr_from_child_;
};
template <class Func>
inline bool ExpectDeath(const char* stmt, Func&& func, DebugInfoMatcher Matcher) {
DeathTest DT(Matcher);
DeathTest::ResultKind RK = DT.Run(func);
auto OnFailure = [&](const char* msg) {
std::cerr << "EXPECT_DEATH( " << stmt << " ) failed! (" << msg << ")\n\n";
if (RK != DeathTest::RK_Unknown) {
std::cerr << "child exit code: " << DT.getChildExitCode() << "\n";
}
if (!DT.getChildStdErr().empty()) {
std::cerr << "---------- standard err ----------\n";
std::cerr << DT.getChildStdErr() << "\n";
}
if (!DT.getChildStdOut().empty()) {
std::cerr << "---------- standard out ----------\n";
std::cerr << DT.getChildStdOut() << "\n";
}
return false;
};
switch (RK) {
case DeathTest::RK_MatchFound:
return true;
case DeathTest::RK_SetupFailure:
return OnFailure("child failed to setup test environment");
case DeathTest::RK_Unknown:
return OnFailure("reason unknown");
case DeathTest::RK_DidNotDie:
return OnFailure("child did not die");
case DeathTest::RK_MatchFailure:
return OnFailure("matcher failed");
}
}
template <class Func>
inline bool ExpectDeath(const char* stmt, Func&& func) {
return ExpectDeath(stmt, func, AnyMatcher);
}
/// Assert that the specified expression throws a libc++ debug exception.
#define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
#define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
#endif // TEST_SUPPORT_DEBUG_MODE_HELPER_H